Создать ссылку на новый объект - PullRequest
11 голосов
/ 01 февраля 2011

Я только изучаю C ++ и натолкнулся на следующую загадку:

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

void myMethod(ParamClass const& param);

Теперь мне интересно, как лучше всего вызвать эти методы. Конечно, каждый вызов будет нуждаться в отдельном объекте, передаваемом в качестве параметра, и, насколько я знаю, единственный способ создать его - это оператор new, поэтому сейчас я делаю следующее:

myObject.myMethod(*new ParamClass(...));

Хотя этот метод полностью работает, мне интересно, нет ли другого уже установленного "c ++ способа" сделать это.

Спасибо за помощь! Dan

Ответы [ 6 ]

13 голосов
/ 01 февраля 2011

Вы должны стараться не использовать new, для начала, так как его использование приносит проблемы с управлением памятью.

Для вашего примера, просто сделайте следующее:

int main(int, char*[])
{
  SomeObject myObject;

  // two phases
  ParamClass foo(...);
  myObject.myMethod(foo);

  // one phase
  myObject.myMethod(ParamClass(...));

  return 0;
}

Я рекомендую первый метод (в два раза), потому что со вторым есть тонкие ошибки.

РЕДАКТИРОВАТЬ : комментарии не совсем подходят для описания ошибок, на которые я ссылался.

Как указывалось @Fred Nurk, в стандарте говорится о некоторых временах жизни временных:

[class.tevent]

(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 ????
}

Argyrios исправил Clang по моей просьбе, чтобы он обнаружил первый случай (и еще несколько, о которых я изначально не думал).Однако второе может быть очень трудно оценить, если реализация forwarder не встроена.

3 голосов
/ 01 февраля 2011

Попробуйте: myObject.myMethod(ParamClass(...)); в C ++, в отличие от Java, вам не всегда нужно произносить new для создания нового объекта.

1 голос
/ 01 февраля 2011

Установленный способ сделать это с помощью автоматической локальной переменной:

ParamClass myParam;
myOjbect.myMethod(myParam);

Используя new, как вы это сделали, вы генерируете утечку памяти.Ничто не избавится от этого объекта, как только функция вернется - в C ++ нет сборки мусора, как в некоторых других языках.

0 голосов
/ 23 августа 2013

Просто обратите внимание, что существует большая разница между присвоением значения объекта (я имею в виду объект пользовательского класса), ранее созданного, новому объекту в java и c ++, и оно примерно равно:

1- в C ++ : объект new = (объект) старше [создать копию объекта старше для нового и при изменении нового, более старый не изменится !]

2- в java : объект новый = (объект) более старый [создать ссылку на более старый объект, а при изменении более нового объекта более старый также изменится (очень очень важно)]

вывод:

в Java: "объект новый = (объект) старше" такой же, как«объект & новый = (объект) старше» в c ++.

0 голосов
/ 01 февраля 2011

Когда вы пишете

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);

Надеюсь, это поможет

0 голосов
/ 01 февраля 2011

Вы должны знать о времени жизни объекта. Если вы передаете *new ParamClass функции, вы передаете право собственности на новый объект этой функции. Если функция не уничтожает ее (и никогда не должна делать это с учетом ссылки), вы получите утечку памяти.

Вместо этого вы должны сделать что-то вроде этого:

ParamClass myParamClass(...);
myObject.myMethod(myParamClass);
...