Почему здесь не вызывается конструктор перемещения? - PullRequest
1 голос
/ 26 мая 2020

Я пытаюсь вызвать конструктор перемещения в приведенном ниже коде, где происходит добавление двух списков. Учитывая то, что я прочитал в книге Страуструпа, конструктор перемещения должен вызываться при возврате operator+(const X& a, const X& b), однако это не соответствует выводам ниже. Вызывается только назначение перемещения.

Кто-нибудь знает, почему конструктор перемещения не вызывается при возврате из функции?

Спасибо

#include <iostream>
#include <list>
using std::list;
using std::cout;
using std::initializer_list;

class X {
  list<int> *p;
  size_t sz;
public:
  X() : p{ new list<int>(0) } { }
  X(size_t size) : p{ new list<int>(size) }, sz {size} { }
  X(initializer_list<int> li) : p{ new list<int>(li) }, sz { li.size() } { }

  X(const X&);
  X& operator=(const X&);

  // move
  X(X&&);
  X& operator=(X&&);

  size_t size() const { return sz; }
  int &operator[](int);
  int &operator[](int) const;

  class size_mismatch { };
};

X::X(const X& a)
{
  p = new list<int>();
  for (auto pp : *(a.p))
    p->push_back(pp);
  sz = a.sz;
}

X& X::operator=(const X& a)
{
  delete p;
  p = new list<int>();
  for (auto pp : *(a.p))
    p->push_back(pp);
  sz = a.sz;
  return *this;
}

X::X(X&& a) : p{ a.p }, sz{ a.sz }
{
  cout << "here0\n";
  a.p = nullptr;
  a.sz = 0;
}


X& X::operator=(X&& a)
{
  cout << "here1\n";
  p = a.p;
  sz = a.sz;
  a.p = nullptr;
  a.sz = 0;
  return *this;
}

int& X::operator[](int x)
{
  for (auto &i : *p) {
    if (x == 0) return i;
    --x;
  }

  throw std::out_of_range("List container");
}

int& X::operator[](int x) const
{
  for (auto &i : *p) {
    if (x == 0) return i;
    --x;
  }

  throw std::out_of_range("List container");
}

X operator+(const X& a, const X& b)
{
  if (a.size()!=b.size())
    throw X::size_mismatch{};

  X res(a.size());

  for (int i = 0; i != a.size(); ++i)
    res[i] = a[i] + b[i];

  return res;
}

int main(int argc, char *argv[])
{
  X px = {0, 1, 2};

  for (int i=0; i < px.size(); i++)
    cout << px[i];
  cout << '\n';

  X py(px);
  for (int i=0; i < py.size(); i++)
    py[i]++;
  for (int i=0; i < py.size(); i++)
    cout << py[i];
  cout << '\n';

  X pz;
  pz = py;
  for (int i=0; i < pz.size(); i++)
    cout << pz[i];
  cout << '\n';

  X ph;
  // This should call move constructor
  ph = px + py + pz;
  for (int i=0; i < ph.size(); i++)
      cout << ph[i];
  cout << '\n';

  return 0;
}

$ g++ -std=c++11 test62.cc && ./a.out
012
123
123
here1
258

1 Ответ

1 голос
/ 26 мая 2020

В этом фрагменте:

X ph;
// This should call move constructor
ph = px + py + pz;

ph уже создано, поэтому нет вопроса о вызове конструктора перемещения.

Если вы измените фрагмент на:

X ph = px + py + pz;

вы по-прежнему не будете вызывать конструктор перемещения из-за исключения копирования.

Вы можете увидеть, что конструктор перемещения вызывается, если вы явно std::move результат в операторе возврата operator+:

X operator+(const X& a, const X& b)
{
  // ...
  return std::move(res);
}

Вот демонстрация .

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