2014-06-26 3 views
2

Я изучил семантику C++ 11 move, и у меня есть такой вопрос.C++ 11 move semantics vs C++ 98

Например:

, если у нас есть

vector<T> vt; // also assume that T have pointers on data in separate memory 
vt.push_back(...); 

предположить vt не хватает неиспользуемых мощностей. Затем в C++ 98 ему будет выделено больше памяти и скопируйте (вызовите конструкторную копию) для каждого объекта T с данными, на которые они указывают.

Например:

t1 -> данные t1 => будут скопированы t_cop1 -> (данные t1_cop1) t2 -> t2 данные => t_cop2 -> (t2_cop2 данные)

C++ 11 ходов семантика позволяет перемещать все объекты T (просто скопировать указатели, но не копировать данные в отдельной памяти, вызвав конструкторы перемещения).

Итак, вопрос в том, почему мы не можем сделать то же самое в C++ 98, почему мы не можем реализовать push_back только для копирования памяти (которая содержит указатели t1, t2, поэтому t_cop1 и t2_cop2 будут созданы с теми же указателями) и после этого освободите его (t1 и t2, используя, например, free(void*))?

UPD: Хорошо, я попытаюсь объяснить мой вопрос о более простом примере:

Например, если у нас есть класс А, который содержит указатель на некоторые данные структуры данных. Мы реализуем конструктор копирования, которая копирует указатель «данные»

class A { 
public: 
    A() {}; 
    A(const A& a) { 
     data = a.data; 
    } 
private: 
    struct Data{}; 
    Data* data; 
}; 

// And I want to implement "move semantics" by calling the copy constructor (that copies just pointer) 

A* a = new A(); 
A* b(a); 

// and then somehow free "a" object (but not call the destructor) 
free(a); // or a = NULL 

Как я понимаю, что это то, что двигаться семантика практически сделать (но оставить в некотором целостном состоянии). Так что, как я думаю, у нас действительно была возможность реализовать переход на старом C++. Не так ли?

Также мы можем сделать то же самое и в предыдущем примере с вектором

+0

Я думаю, что вы не поняли семантику перемещения ... –

+0

Здесь нет разницы между C++ 11 и C++ 98, потому что при перемещении указателей только что скопированы указатели. Также 'vector ', где 'T' - это указатель, будет перемещаться только по указателям и никогда не указывать указатель. – nwp

+0

Exectly, но C++ 98 вызовет глубокую копию, чтобы скопировать не только указатели, но и все данные, на которые указывают указатели. Поэтому возникает вопрос, почему мы не можем реализовать семантику перемещения с помощью C++ 98 – Nikita

ответ

0

«Переместить семантику» предоставляет способ компилятор передавать ссылки на такие вещи, как конструкторам, которые могут быть дифференцированы в качестве ссылок Lvalue (вид, который Вы» re used to, найденный в C++ 98) и rvalue ссылки (новый с C++ 11, используя нотацию &&, они относятся к объектам, которые являются временными и промежуточными и, вероятно, не будут проходить мимо текущего оператора).

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

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

Вы не можете сделать эквивалент как конструктор (и, следовательно, с временным объектом) в C++ 98, поскольку он знает только, как сделать копию. Существует способ достижения аналогичного эффекта с помощью функции swap() (и метода в некоторых классах), но это должно было быть написано явно. (В основном, чтобы переместить содержимое контейнера a в недавно построенном пустой контейнер b, вы могли бы назвать swap(a, b);, а затем уничтожить a, который затем будет пуст.)


Один пример случая, когда вы просто можете» т делать правильные вещи в C++ 98 инициализирует вектор с результатом функции, которая возвращает вектор:

vector<int> fibonacci(int n) { 
    vector<int> result; 
    if(n <= 0) return result; 
    result.push_back(0); 
    if(n <= 1) return result; 
    result.push_back(1); 
    for(int i = 1; i < n; ++i) 
     result.push_back(result[i] + result[i - 1]); 
    return result; 
} 

vector<int> datavect = fibonacci(10); 

C++ 98 и C++ 11 будет и обходить молчанием прочь функцию возврата копии (создавая result в месте, где сохраняется возвращаемое значение), но C++ 98 может o nly вызовите конструктор копирования для datavect, потому что семантики перемещения не существует. C++ 11 вместо этого может вызвать конструктор перемещения, который может переместить хранилище из временного возвращаемого значения в datavect. В C++ 98 на самом деле нет способа сделать это, не получая operator new и operator delete задействованные и возвращающие указатели вместо объектов, избивая (без детерминированного времени) свободное хранилище без усиления.

+0

Да, это то, что делают семантики перемещения. Итак, мой вопрос в том, как (или почему нет) мы не можем реализовать семантику перемещения в C++ 98? – Nikita

+0

См. Мой последний абзац. Короче: вы должны сделать это вручную и не можете делать это вообще в некоторых случаях, как функции, возвращающие контейнеры (в отличие от указателей или ссылок). –

+0

Да, я согласен, что в случаях свопа и фибоначчи старый C++ не подходит. Но в моем примере (и с помощью вектора) производительность может быть улучшена путем эмуляции семантики перемещения. Итак, почему они не реализовали его в stl до C++ 11? – Nikita

Смежные вопросы