Почему конструктору копирования не нужно проверять, указывает ли входной объект на себя или нет? - PullRequest
3 голосов
/ 30 мая 2020

Как показано в приведенном ниже коде, оператор присваивания копии должен проверять, указывает ли входной объект на себя или нет. Интересно, почему конструктору копирования не нужно выполнять ту же проверку.

Я новичок в C ++. Буду благодарен за помощь по этому вопросу.

  class rule_of_three
    {
        char* cstring; // raw pointer used as a handle to a dynamically-allocated memory block

        void init(const char* s)
        {
            std::size_t n = std::strlen(s) + 1;
            cstring = new char[n];
            std::memcpy(cstring, s, n); // populate
        }
     public:
        rule_of_three(const char* s = "") { init(s); }

        ~rule_of_three()
        {
            delete[] cstring;  // deallocate
        }

        rule_of_three(const rule_of_three& other) // copy constructor
        { 
            init(other.cstring);
        }

        rule_of_three& operator=(const rule_of_three& other) // copy assignment
        {
            if(this != &other) {
                delete[] cstring;  // deallocate
                init(other.cstring);
            }
            return *this;
        }
    };

Ответы [ 2 ]

3 голосов
/ 30 мая 2020

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

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

Из-за этого традиционно конструкторы копирования (и перемещения) не проверяют &other != this.

Но ничего мешает вам делать это, если вам нужна дополнительная безопасность:

rule_of_three(const rule_of_three& other) // copy constructor
{ 
    assert(&other != this);
    init(other.cstring);
}

1 [basic.life]/7 кажется, позволяет это, пока вы не получаете доступ к самому еще не созданному объекту. Допускается взятие адреса с помощью &.

0 голосов
/ 30 мая 2020

Предположим, у вас есть простые объекты, такие как Stormtroopers:

class Stormtrooper
    {
        char* cstring; // raw pointer used as a handle to a dynamically-allocated memory block

        void clone(const char* s)
        {
            std::size_t n = std::strlen(s) + 1;
            cstring = new char[n];
            std::memcpy(cstring, s, n); // populate
        }
     public:
        Stormtrooper(const char* s = "I am a Stormtrooper clone") { clone(s); }

        ~Stormtrooper()
        {
            delete[] cstring;  // deallocate
        }

        Stormtrooper(const Stormtrooper& other) // copy constructor
        { 
            clone(other.cstring);
        }

        Stormtrooper& operator=(const Stormtrooper& other) // copy assignment
        {
            if(this != &other) {
                delete[] cstring;  // deallocate
                clone(other.cstring);
            }
            return *this;
        }
    };

Если вы хотите назначить une Stormtrooper другому, полезно проверить, идентичны ли эти два Stormtroopers или нет (как правило, они идентичны) . Таким образом вы избегаете операции clone (), потому что штурмовики уже идентичны.

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

Таким образом вы можете довольно легко создать целую армию штурмовиков.

...