Создать ссылку на новый объект
Я просто изучаю С++, и я столкнулся с следующей загадкой:
Как новичок в С++, я читал, что использование ссылки вместо указателей (когда это возможно), как правило, является хорошей идеей, поэтому я пытаюсь привыкнуть раньше. В результате у меня есть много методов, которые имеют общий вид
void myMethod(ParamClass const& param);
Теперь мне интересно, как лучше всего назвать эти методы. Конечно, для каждого вызова потребуется другой объект, переданный как параметр, и насколько я знаю, единственный способ создать его - это новый оператор, поэтому теперь я делаю следующее:
myObject.myMethod(*new ParamClass(...));
В то время как этот метод полностью работает, мне интересно, нет ли другого уже установленного "С++-способа" этого.
Спасибо за помощь!
Dan
Ответы
Ответ 1
Вы должны стараться не использовать new
, для начала, поскольку использование этого приводит к проблемам управления памятью.
В качестве примера выполните следующие действия:
int main(int, char*[])
{
SomeObject myObject;
// two phases
ParamClass foo(...);
myObject.myMethod(foo);
// one phase
myObject.myMethod(ParamClass(...));
return 0;
}
Я рекомендую первый метод (в два раза), потому что есть тонкие gotchas со вторым.
EDIT: комментарии не подходят для описания gotchas, о котором я говорил.
Как сказано в @Fred Nurk
, в стандарте говорится несколько вещей о времени жизни временных файлов:
[class.temporary]
(3) Временные объекты уничтожаются как последний шаг при оценке полного выражения (1.9), который (лексически) содержит точку, в которой они были созданы. Это справедливо, даже если эта оценка заканчивается выбросом исключения. Вычисления значений и побочные эффекты уничтожения временного объекта связаны только с полным выражением, а не с каким-либо конкретным подвыражением.
(5) Временная привязка ссылки или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется для срока службы ссылки [примечание: за исключением нескольких случаев... ]
(5) [такой как...] Временная привязка к эталонному параметру в вызове функции (5.2.2) сохраняется до завершения полного выражения, содержащего вызов.
Это может привести к двум тонким ошибкам, которые большинство компиляторов не улавливают:
Type const& bound_bug()
{
Type const& t = Type(); // binds Type() to t, lifetime extended to that of t
return t;
} // t is destroyed, we've returned a reference to an object that does not exist
Type const& forwarder(Type const& t) { return t; }
void full_expression_bug()
{
T const& screwed = forwarder(T()); // T() lifetime ends with `;`
screwed.method(); // we are using a reference to ????
}
Аргириос заплатил Кланг по моей просьбе, чтобы он обнаружил первый случай (и еще несколько, на самом деле, о которых я изначально не думал). Однако второй может быть очень сложно оценить, не реализована ли реализация forwarder
.
Ответ 2
Try:
myObject.myMethod(ParamClass(...));
в С++, в отличие от Java, вам не всегда нужно указывать new
для создания нового объекта.
Ответ 3
Установленный способ сделать это с автоматической локальной переменной:
ParamClass myParam;
myOjbect.myMethod(myParam);
Используя new
так, как вы это делали, вы генерируете утечку памяти. Ничего не удалит этот объект после возвращения функции - у С++ нет сборки мусора, как это делают некоторые другие языки.
Ответ 4
Вам нужно знать время жизни объекта. Если вы передадите функцию *new ParamClass
в функцию, вы передадите ей право собственности на новый объект. Если функция не уничтожает его (и он никогда не должен делать этого с учетом ссылки), вы получите утечку памяти.
Вместо этого вы должны сделать что-то вроде этого:
ParamClass myParamClass(...);
myObject.myMethod(myParamClass);
Ответ 5
Когда вы пишете
myObject.myMethod(*new ParamClass(...));
вы теряете указатель на новый объект. То есть, это сработает, но вы не сможете позже delete
объекта. Итак, вы можете сделать это:
ParamClass pc(...);
myObject.myMethod(pc);
или, проще
myObject.myMethod(ParamClass(...));
или, если динамическое распределение необходимо для какой-то необъяснимой причины
ParamClass* pPc = new ParamClass(...);
myObject.myMethod(*pPc);
...
delete pPc;
или используйте интеллектуальные указатели, чтобы избежать ручного удаления. Что-то вроде:
boost::scoped_ptr<ParamClass> spPc(new ParamClass(...));
myObject.myMethod(*pPc);
Надеюсь, что это поможет
Ответ 6
Заметим, что существует большая разница между назначением значения объекта (я имею в виду объект определяемого пользователем класса), ранее созданного для нового объекта в java и С++
, и речь идет о:
1- в С++: объект new = (объект) старше [создайте копию объекта старше и более поздней, а когда вы измените новое, более старое не будет изменено ]
2- в java: объект new = (объект) старше [создайте ссылку на старый объект, а когда вы измените новое, более старое и будет изменено ( очень важно)]
заключение:
в java: "object new = (объект) старше" совпадает с "object & new = (object) старше" в С++.