Почему поведение меняется при изменении порядка emplace_back / push_back? Почему количество Конструкторов увеличивается? - PullRequest
0 голосов
/ 26 марта 2020
class Buffer
{
    unsigned char* ptr{nullptr};
    size_t length{0};
public:
    Buffer() :
    ptr(nullptr),
    length(0)
    {std::cout<<"\n In Buffer()\n";}


    explicit Buffer(size_t const size):
    ptr(new unsigned char[size] {0}),
    length (size)
    {std::cout<<"\n In explicit Buffer(size_t const size)\n";}

    ~Buffer()
    {
        if (nullptr != ptr)     delete [] ptr;
    }


//     Causing runtime nullptr exception
//     Buffer(Buffer const& obj) :
//     ptr(new unsigned char[obj.length] {0}),
//     length (obj.getLength())
//     {   std::cout<<"\n In Buffer(Buffer const& obj)\n";}

    // Unnessary Fixed Copy Constructor
    Buffer(Buffer const& obj) noexcept
    {
        std::cout<<"\n In Buffer(Buffer const& obj)\n";
        std::cout<<"\n obj Details : Length = "<<obj.getLength()<<std::boolalpha<<": (ptr == nullptr) = "<<(nullptr == obj.getPtr())<<"\n";
        if (obj.length == 0)
            ptr = nullptr;
        else
            ptr = new unsigned char[obj.length] {0};
        length = obj.length;
    }

    Buffer& operator=(Buffer const obj)
    {
        std::cout<<"\n In Buffer& operator=(Buffer const obj)\n";
        if (this == &obj)   return *this;
        delete [] this->ptr;
        this->ptr = new unsigned char[obj.length]{0};
        this->length = obj.length;
        return *this;
    }

    Buffer(Buffer && data)
    {
        std::cout<<"\n In Buffer(Buffer && data)\n";
        std::cout<<"\n obj Details : Length = "<<data.getLength()<<std::boolalpha<<": (ptr == nullptr) = "<<(nullptr == data.getPtr())<<"\n";
        ptr = data.ptr;
        length = data.length;
        data.ptr = nullptr;
        data.length = 0;
    }

    Buffer& operator=(Buffer&& data)
    {
        std::cout<<"\n In Buffer& operator=(Buffer&& data)\n";
        if (this == &data)  return *this;
        this->ptr = data.ptr;
        this->length = data.length;
        data.ptr = nullptr;
        data.length = 0;
        return *this;
    }

    size_t getLength() const {return length;}
    unsigned char* getPtr() const {return ptr;}
};

--------- КОД драйвера ---------

std::vector<Buffer> v;
std::cout<<"\nemplace_back()\n";
v.emplace_back();
std::cout<<"\npush_back(Buffer(2))\n";
v.push_back(Buffer(2));

--------- Вывод с помощью конструктора копирования книг ---------

emplace_back ()

в буфере ()

push_back (буфер (2))

в явном буфере (size_t const size)

в буфере (данные буфера &&)

obj Подробности: длина = 2: (ptr == nullptr) = false libc ++ abi.dylib: завершается с неисследованным исключением типа std :: bad_allo c: std :: bad_allo c

--------- Вывод с нестандартным исправлением в конструкторе копирования ---------

emplace_back ()

In Buffer ()

push_back (Buffer (2))

В явном буфере (размер размера const)

В буфере (Buffer && data)

obj Подробности: Длина = 2: (ptr == nullptr) = false

В буфере (Buffer const & obj)

obj Подробности: Длина = 0: (ptr == nullptr) = true Программа завершилась с кодом выхода: 0

--------- КОД драйвера ---------

std::vector<Buffer> v;
std::cout<<"\npush_back(Buffer(2))\n";
v.push_back(Buffer(2));
std::cout<<"\nemplace_back()\n";
v.emplace_back();

--------- Вывод с константой копирования книги ructor ---------

push_back (Buffer (2))

В явном буфере (размер const size_t)

в буфере (данные буфера &&)

obj Подробности: длина = 2: (ptr == nullptr) = false

emplace_back ()

в буфере ()

в буфере (буфере const & obj) Программа завершилась с кодом выхода: 0

--------- Вывод с неосторожным исправлением в конструкторе копирования ---------

push_back (Buffer (2))

В явном буфере (размер константы size_t)

В буфере (данные буфера &&)

obj Подробности: длина = 2: (ptr == nullptr) = false

emplace_back ()

в буфере ()

в буфере (Buffer const & obj)

obj Подробности: длина = 2: (ptr = = nullptr) = false

Программа завершилась с кодом выхода: 0

1 Ответ

0 голосов
/ 28 марта 2020

new unsigned char[obj.length] {0} демонстрирует неопределенное поведение, когда obj.length == 0.

[expr.new] / 7 Выражение в noptr -new-декларатор ошибочен, если:
(7.4) - new-initializer представляет собой braced-init-list и количество элементов массива, для которых инициализаторы предоставляются ... превышает количество элементов для инициализации.

" Выражение " здесь относится к размеру массива в квадратных скобках.

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


Возможно, вы захотите пометить ваш конструктор перемещения noexcept, тогда вектор будет использовать его при перераспределении вместо конструктора копирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...