«переходить» из стека в кучу? - PullRequest
0 голосов
/ 05 февраля 2019

Мне нужно написать оболочку C вокруг библиотеки C ++, и мне нужны объекты, расположенные в куче.Функции и методы библиотеки C ++ используют и возвращают объекты, расположенные в стеке.

Я знаю, я могу "перенести" объект из стека в кучу с помощью копирования, т.е. auto heapObj = new Foo(stackObj);, но хотел бы избежать копированияи попробуйте вместо этого move, если смогу.

Кажется, это "работает" (к моему удивлению).За кулисами происходит копия?Если нет, безопасно ли использовать этот шаблон?

main.h

class Foo {
   public:
    std::vector<int> big;

    explicit Foo(size_t len);

    Foo(Foo&& other) noexcept;

    // remove copy constructor
    Foo(const Foo &) = delete;

    // delete assignment operator
    Foo &operator=(const Foo &) = delete;


    size_t size();
};

main.cpp

#include <iostream>
#include "main.h"

Foo::Foo(size_t len) : big(len) {}

Foo::Foo(Foo&& other) noexcept : big(std::move(other.big)) {}

size_t Foo::size() { return this->big.size(); }

int main() {
    Foo ms(1000);  // on the stack
    ms.big[0] = 42;

    auto mh = new Foo(std::move(ms));  // on the heap (no copy?)

    std::cout << mh->size() << ", " << mh->big[0] << std::endl;

    delete mh;
}

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Каждый раз, когда движение "действительно происходит", это потому, что внутри перемещенной вещи есть некоторый косвенный ресурс .Некоторый ресурс, на который ссылается дескриптор, который можно дешево поменять местами (например, скопированный указатель; указатель остается там, где он был).Обычно это достигается с помощью указателей на динамически размещаемые объекты, такие как данные, хранящиеся в векторе.

То, что вы пытаетесь переместить, - это вектор.Таким образом, он уже динамически распределен , и перемещение легко.На самом деле не имеет значения, где находится реальный объект std::vector и где живет Foo - если есть косвенный ресурс, перемещение возможно.

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

0 голосов
/ 05 февраля 2019

Прежде всего, перемещение int или указателя эквивалентно копии.То есть, если у вас было

struct X {
  int a, b;
  int* data;
};

, то его перемещение не будет дешевле, чем его копирование (пока игнорируем владение data).По совпадению, вышесказанное в основном то, как выглядит std::vector издалека: член size и capacity плюс некоторый указатель на кусок памяти.

Важная вещь о перемещении по сравнению с копированием - это то, что происходит с владением ресурсами .std::vector владеет некоторой кучей памяти (data).Если вы копируете a std::vector, то эта кучная память должна быть скопирована, чтобы и оригинал, и копия могли владеть своими собственными данными.Но если вы переместите его, тогда только вектор перемещения должен сохранить владение, поэтому указатель data может быть передан от одного к другому (вместо всех данных), потому что владение можетбыть «украденным» из перемещенного объекта.

Вот почему нет никакого конфликта в «перемещении» вашего объекта из стека в кучу: сам объект по-прежнему в основном копируется из одного места в другое, но ресурсы, которыми он (или его подобъекты, такие как big) владеют, не копируются, а перемещаются («украдены»).

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