Есть явная копия

Я ищу такой синтаксис:

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() функция к классу, но он не может заменить конструктор копирования.

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

Другие вопросы по тегам