Передача права собственности на объект стека без дублирования - PullRequest
1 голос
/ 28 февраля 2020

Сторонняя библиотека имеет API Huge computeHuge(). Он возвращает сам объект, а не ссылку / указатель. У меня нет контроля над объектом или API.

У меня есть два класса:

class Bar {
  Huge h;
  Bar(Huge &huge): h(huge);
}

class Foo {
  Bar b;

  Foo() {
    Huge h = computeHuge();
    b = Bar(h);
  }

К сожалению, в результате этого дизайна (временно) получаются две копии огромного объекта: один копия существует в конструкторе Foo, а другая существует внутри объекта Bar. После выхода из конструктора Foo остается только одна копия, но мне нужно удвоить объем памяти внутри конструктора. Поскольку h может составлять сотни ГБ, это имеет значение.

Одно из решений этой проблемы - сделать Foo владельцем h:

class Bar {
  Huge &h;
  Bar(Huge &huge): h(huge);
}

class Foo {
  Bar b;
  Huge h;

  Foo() {
    h = computeHuge();
    b = Bar(h);
  }

Это успешно устраняет иметь две копии h, но в моем приложении это не имеет смысла: Bar - это то, что нужно h. Как я могу:

  1. Вызвать computeHuge() в конструкторе Foo
  2. Позволить Bar сохранить право собственности на h
  3. Все без когда-нибудь нужны две копии h в памяти?

1 Ответ

2 голосов
/ 28 февраля 2020

Если Huge является подвижным, это не делает никаких копий:

class Bar {
  Huge h;
  Bar(Huge huge): h(std::move(huge)) {}   // move huge into its final place, h
};

class Foo {
  Bar b;

  Foo() {
    Huge h = computeHuge();
    b = Bar(std::move(h));   // move h into constructor argument
    // h cannot be used here anymore
  }
};

Для целей отладки это (крошечный) Huge, который не может быть скопирован, но только перемещен. Каждая попытка копирования является ошибкой компилятора:

struct Huge {
    Huge() = default;
    Huge(Huge&& other) { std::cout << "move "; }
    Huge(const Huge& other) = delete;
    Huge& operator=(Huge&& other) { std::cout << "move= "; return *this; }
    Huge& operator=(const Huge& other) = delete;
};
...