Есть ли способ назначить сложенный объект выделенной памяти, используя новое размещение? - PullRequest
0 голосов
/ 31 октября 2018

Вот моя программа:

#include <iostream>

using namespace std;

class Object {
public:
    Object() { cout << "Object constructor!" << endl; }
    ~Object() { cout << "Object destructor!" << endl; }
    Object(const Object& obj) { information = obj.information; cout << "Copy constructor!" << endl; }
    void setInformation(const string info) { information = info; }
    string getInformation() const { return information; }
private:
    string information;
};

class Storage {
public:
    Storage() { object = static_cast<Object*>(operator new(sizeof(Object))); }
    ~Storage() { operator delete(object); }

    void setObject(const Object& obj) {
        // Todo: assign obj to the allocated space of the pointer object
    }
private:
    Object* object;
};

int main()
{
    Object o;
    o.setInformation("Engine");
    Storage storage;
    storage.setObject(o);
    return 0;
}

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

object = new(object) Object()

чтобы построить объект. Но могу ли я поместить в память объект, который уже создан? В моем случае вызов метода setObject (). Если да, с какими проблемами я могу столкнуться при таком управлении памятью? Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 31 октября 2018

Placement new - довольно продвинутая конструкция, и мысль о наличии Object*, которая фактически указывает на неинициализированную память, довольно ужасна. Могу ли я предложить вам сделать вашу жизнь проще?

class Storage {
    void setObject(const Object& obj) {
        if (object) {
            *object = obj;
        } else {
            object.reset(new Object(obj));
        }
    }
private:
    std::unique_ptr<Object> object;
};

Для этого требуется конструктор копирования и оператор присваивания в классе Object, но он гораздо более идиоматичен в C ++. И в реализации Object, как показано, стандартные реализации, предоставляемые компилятором, уже в порядке.

0 голосов
/ 31 октября 2018

Просто чтобы уточнить:

Но можно ли поместить в память уже созданный объект?

Нет, вы не можете. Нет способа, как перемещать объекты в памяти в C ++. Для тривиально копируемых типов вы можете скопировать (например, memcpy или memmove) их представления памяти. Но это на самом деле ничего не двигает. Более того, ваш класс Object не является копируемым.

Что вы можете move - это содержимое объектов, для чего и нужна семантика перемещения.

0 голосов
/ 31 октября 2018

Простейшим способом реализации поведения, которое вы пытаетесь реализовать, будет использование std::optional из C ++ 17. Это позволит вам «зарезервировать» память для вашего Object без его создания и без использования кучи . Он также будет обрабатывать все вызовы конструктора и деструктора.

Это также можно сделать без std::optional, но вам, по сути, придется реализовать подобное решение самостоятельно. В любом случае вам понадобится дополнительный член, чтобы указать, создан объект или нет, чтобы вы могли правильно обрабатывать уничтожение и присваивание.

Тогда ваш setObject метод будет выглядеть примерно так:

void setObject(const Object& obj) {
    if (constructed) {
        *object = obj;
    } else {
        new (object) Object(obj);
        constructed = true;
    }
}

Чтобы использовать семантику перемещения, вы можете изменить свой метод следующим образом:

void setObject(Object obj) {
    if (constructed) {
        *object = std::move(obj);
    } else {
        new (object) Object(std::move(obj));
        constructed = true;
    }
}

Обратите внимание, что теперь setObject принимает значение параметра по значению, поэтому его можно использовать как со ссылками lvalue, так и со значением rvalue для создания параметра, который затем будет перемещен в член.

...