Подтвердить что ты не робот

Оператор присваивания с ссылочными элементами

Является ли это допустимым способом создания оператора присваивания с элементами, которые являются ссылками?

#include <new>

struct A
{
    int &ref;
    A(int &Ref) : ref(Ref) { }
    A(const A &second) : ref(second.ref) { }
    A &operator =(const A &second)
    {
        if(this == &second)
            return *this;
        this->~A();
        new(this) A(second);
        return *this;
    }
}

Кажется, он компилируется и работает нормально, но с склонностью С++ к поверхностному поведению undefined, когда наименее ожидаемый, и всем людям, которые говорят, что это невозможно, я думаю, что есть некоторые gotcha, которые я пропустил. Я что-то пропустил?

4b9b3361

Ответ 1

Синтаксически корректно. Однако, если размещение новых бросков, вы в конечном итоге с объектом, который вы не можете уничтожить. Не говоря уже о катастрофе если кто-то вытекает из вашего класса. Только не делай этого.

Решение прост: если класс должен поддерживать назначение, не используйте любые ссылочные элементы. У меня много классов, которые берут ссылку аргументы, но сохраните их в качестве указателей, так что класс может поддерживать назначение. Что-то вроде:

struct A
{
    int* myRef;
    A( int& ref ) : myRef( &ref ) {}
    // ...
};

Ответ 2

Что вы делаете, насколько мне известно, технически корректно, но это порождает проблемы. Например, рассмотрите, что происходит с производным классом из A, так как его оператор присваивания генерирует новый объект (разрезание). Не можете ли вы просто превратить ссылку в указатель внутри своего класса?

Кроме того, конструкторы копирования и операторы присваивания обычно принимают свой аргумент const&.

Ответ 3

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

Вы должны реализовать его, используя Идиома копирования и свопинга. Это по крайней мере 3 преимущества по сравнению с вашей реализацией.

Ответ 4

Другим решением является использование класса reference_wrapper (в функциональном заголовке):

struct A
{
    A(int& a) : a_(a) {}
    A(const A& a) : a_(a.a_) {}

    A& operator=(const A& a)
    {
        a_ = a.a_;
        return *this;
    }

    void inc() const
    {
        ++a_;
    }

    std::reference_wrapper<int>a_;

};