Создать ссылку на новый объект

Я просто изучаю С++, и я столкнулся с следующей загадкой:

Как новичок в С++, я читал, что использование ссылки вместо указателей (когда это возможно), как правило, является хорошей идеей, поэтому я пытаюсь привыкнуть раньше. В результате у меня есть много методов, которые имеют общий вид

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) старше" в С++.