Конструкторы копирования C ++ - PullRequest
0 голосов
/ 02 января 2009

Я недавно написал кусок кода, который сделал

SomeClass someObject;
mysqlpp::StoreQueryResult result = someObject.getResult();

где SomeClass :: getResult () выглядит так:

mysqlpp::StoreQueryResult SomeClass::getResult()
{
mysqlpp::StoreQueryResult res = ...<something>...;
return res;
}

Теперь, используя пример из первого фрагмента кода, когда я скомпилировал и запустил программу, произошел сбой с сигналом ABORT. Затем я изменил первый фрагмент на:

SomeClass someObject;
mysqlpp::StoreQueryResult result(someObject.getResult());

, который работал нормально. Кроме того, просто чтобы попробовать это, я изменил это снова:

SomeClass someObject;
mysqlpp::StoreQueryResult result;
result = someObject.getResult();

, который также работал нормально.

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

Короче, в чем разница:

FooClass a = someObject.someMethodReturningFooClassInstance();

и

FooClass a(someObject.someMethodReturningFooClassInstance());?

Мухос, спасибо!

Ответы [ 6 ]

4 голосов
/ 02 января 2009

Я не думаю, что есть разница в обоих случаях. Один и тот же конструктор копирования вызывается оба раза.

Вы уверены, что это точно то, что вы написали в своем коде?

2 голосов
/ 02 января 2009

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

Хорошо, мое первоначальное предположение было неверным, и, по-видимому, в обоих случаях вызывался бы только конструктор копирования (хорошо в случае присваивания также может быть вызван дополнительный конструктор "преобразования"). После некоторого сна я включу компилятор и проверю это в моей среде разработки.

1 голос
/ 02 января 2009

Вы можете просто поместить точку останова (или даже оператор printf) в конструктор копирования, и вы точно знаете, когда он вызывался, вы знаете. ТАК не может заменить базовую отладку. ;)

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

Вы пытались запустить его в отладчике? Он должен сломаться при сигнале ABORT.

0 голосов
/ 02 января 2009

Я думаю, что в первом случае объекту присваивается значение (правильное значение). Это отправляет значение объекту. В 2,3 exmple - это неявный объект и концепция явного объекта. Вам не следует писать код по назначенному значению для прямого объекта. *

0 голосов
/ 02 января 2009

Ну, на самом деле первый будет делать промежуточную копию с оператором =, а второй - конструкцию прямой копии.

0 голосов
/ 02 января 2009

В самой чистой теории конструктор копирования должен вызываться в обоих случаях. Тем не менее, есть нечто, называемое оптимизацией возвращаемого значения (RVO), которое компилятору разрешено использовать в этих случаях. Если используется RVO, конструктор копирования не будет вызван. Возможно, ваш компилятор использует RVO в одном случае, а не в другом?

Edit: Это относится только к делу

SomeClass someObject;
mysqlpp::StoreQueryResult result;
result = someObject.getResult();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...