Как заставить std :: vector использовать конструктор перемещения вместо копии? - PullRequest
0 голосов
/ 29 апреля 2020

Я хочу использовать семантику перемещения в своем приложении, а не копировать данные. Вот код:

using namespace std;

struct TestData
{
    TestData(const TestData&) = delete;
    TestData& operator=(const TestData&) = delete;
    TestData(TestData &&other) = default;
    TestData& operator=(TestData &&other) = default;

    TestData() { std::cout << "TestData()" << std::endl; }
    ~TestData() noexcept {
        if(ptr != null) delete []ptr;
        std::cout << "~TestData(), ptr = " << (ptr == nullptr ? "nullptr" : "not null") << std::endl; 
    }
    int x;
    char *ptr = nullptr;
};

void add(std::vector<TestData> &vector)
{
    TestData d;
    d.x = 1;
    d.ptr = new char[12];
    memcpy(d.ptr, "Test string", 11);
    vector.push_back(d);
}


int main()
{
    std::vector<TestData> v;
    add(v);
    add(v);

    return 0;
}

Но компилятор G CC завершается с ошибкой:

ошибка: использование удаленной функции 'TestData :: TestData (const TestData &) '

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

Итак, вопрос - как заставить G CC использовать конструктор перемещения?

  • G CC v. 9.3.0
  • Ubuntu 20.04

1 Ответ

3 голосов
/ 29 апреля 2020

Этот вызов

vector.push_back(d);

не вызывает ваш конструктор перемещения, поскольку d не является ссылкой на r-значение. Было бы плохо, если бы конструкторы перемещения вызывались для ссылок, не имеющих значения r, потому что это вырвало бы кишки из объектов, которые должны оставаться нетронутыми. Вам нужно привести к r-значению, чтобы сделать явным, что вам больше не нужен d. И это то, что делает std::move (на самом деле это не что иное, как приведение):

vector.push_back(std::move(d));

Однако конструктор перемещения по умолчанию TestData не делает правильных действий. После строки выше ptr все еще принадлежит перемещенному объекту, что приводит к двойному удалению. Вы можете предотвратить это, и проблема с тем, что ваша строка не заканчивается на ноль, используя std::string в качестве члена вместо char *.

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