Есть явная копия
Я ищу такой синтаксис:
class Hugo
{
Hugo();
explicit Hugo( const Hugo& hugo );
Hugo GetRandomHugo()
{
Hugo hugo;
hugo.value = rand();
// this would fail:
// return hugo;
return Hugo(hugo); // explicit copy!!
}
};
Другими словами: я ищу явный синтаксис копирования, чтобы позволить методам возвращать копию, даже если мой конструктор копирования является явным.
Я использую GCC 4.4.5.
Большое спасибо,
Charly
3 ответа
Вы не можете: возврат по значению является неявной конструкцией копирования. Здесь, return пытается неявно скопировать ваш явно созданный экземпляр временного.
От 8.5/12:
Инициализация, которая происходит при передаче аргумента, возврате функции, выдаче исключения (15.1), обработке исключения (15.3) и заключенных в скобки списках инициализаторов (8.5.1), называется copy-initialization и эквивалентна форме:
T x = a;
Вы можете обойти это, имея явный HugoCopy
класс как следующий
class HugoCopy;
class Hugo {
public:
Hugo() { ... }
Hugo(HugoCopy const&);
explicit Hugo(Hugo const&) { ... }
};
struct HugoCopy {
HugoCopy(Hugo const& hugo)
:hugo(hugo)
{ }
Hugo const& hugo;
};
Hugo::Hugo(HugoCopy const&) { ... }
Теперь применяется следующая семантика
Hugo a;
Hugo b = a; // forbidden
Hugo c(a); // allowed
Hugo d = HugoCopy(a); // allowed
Hugo f() {
Hugo a;
return a; // forbidden
return HugoCopy(a); // allowed
}
Кроме того, вы можете использовать функцию преобразования
class Hugo {
public:
Hugo() { ... }
explicit Hugo(Hugo const&) { ... }
};
struct HugoCopy {
HugoCopy(Hugo const& hugo)
:hugo(hugo)
{ }
operator Hugo const&() { return hugo; }
private:
Hugo const& hugo;
};
Это опирается на тонкий угол языка C++. Так что, если вы используете это, вам лучше знать, что вы делаете, или не делаете этого: сначала он вызывает функцию преобразования в HugoCopy (или, в первом случае, в конструкторе Hugo
) чтобы получить Hugo
/ Hugo const&
, а затем он напрямую инициализирует пункт назначения Hugo
возразить с этим Hugo
объект. GCC не нравится код, но Clang и Comeau/EDG принимают его в соответствии с вышеуказанной семантикой.
return Hugo(hugo);
это просто создает одну дополнительную копию перед возвратом. Фактический оператор возврата затем берет эту копию и копирует ее снова. Весь смысл в конструкторе копирования заключается в том, что он может использоваться неявно, всякий раз, когда нам или компилятору требуется скопировать объект.
Если вам нужен явный синтаксис, вы можете просто добавить Clone()
или же Copy()
функция к классу, но он не может заменить конструктор копирования.
Каждый раз, когда компилятору необходимо скопировать объект (например, при передаче его по значению в качестве параметра функции или при возврате его из функции), ему необходимо создать копию объекта. Вы не можете сделать это для компилятора, потому что вы не видите код перехода между вызывающим и вызываемым. Вы можете скопировать объект внутри вызываемой функции или за ее пределы, но у вас нет возможности скопировать его из тела вызывающего. Только компилятор может сделать это, и для того, чтобы сделать это, он должен иметь возможность копировать объект по желанию - что делается с помощью конструктора копирования.