2016-02-15 4 views
11

Есть ли преимущества использования std::vector::emplace_back и std::move? или он просто лишний, так как std::vector::emplace_back сделает inplace-construction?std :: vector :: emplace_back и std :: move

Чехлы для осветления:

std::vector<std::string> bar; 

Первое:

bar.emplace_back(std::move(std::string("some_string"))); 

Второе:

std::string str("some_string"); 
bar.emplace_back(std::move(str)); 

Третье:

bar.emplace_back(std::move("some_string")); 
+1

Третий ход, по крайней мере, бессмыслен. Эта буквальная строка содержит const, поэтому ее нельзя перемещать. –

ответ

13

Во второй версии есть преимущество. Вызов emplace_back вызовет конструктор перемещения std::string, когда используется std::move, которое может сохранить на копии (пока эта строка не будет сохранена в буфере SSO). Обратите внимание, что в этом случае это по существу то же самое, что и push_back.

std::move В первой версии нет необходимости, так как строка уже является prvalue.

std::move в третьей версии не имеет значения, поскольку строковый литерал не может быть перемещен.

Самый простой и наиболее эффективный метод заключается в следующем:

bar.emplace_back("some_string"); 

Это не требует никаких ненужных std::string конструкций, как в буквальном смысле идеально-пересылаются в конструктор.

+0

Не могли бы вы прояснить «то же, что и« push_back »в этом случае?» В таком случае точно? Может ли 'emplace_back' всегда заменяться на' push_back', если его аргумент 'move'd? –

1

Во втором случае есть смысл сделать это. Рассмотрим этот код:

int main() 
{ 
    std::vector<std::string> bar; 
    std::string str("some_string"); 
    bar.emplace_back(std::move(str)); 
    // bar.emplace_back(str); 
    std::cout << str << std::endl; 
} 

Если изменить комментарий к строке выше, вы можете видеть, что вы будете в конечном итоге с двумя копиями «some_string» (один в bar и один в str). Так что это что-то меняет.

В противном случае первый движется временно, а третий перемещает постоянный строковый литерал. Он ничего не делает.

2

Идея emplace_back состоит в том, чтобы избавиться от операций копирования и перемещения. Вам просто нужно передать входные параметры std::string в emplace_back. Объект std::string будет построен внутри метода emplace_back.

bar.emplace_back("some_string"); 

Если у вас уже есть строка, то имеет смысл использовать std::move. Объект std::string будет построен внутри emplace_back путем перемещения данных от str.

std::string str("some_string"); 
bar.emplace_back(std::move(str)); 
4

emplace_back вызовы somehthing как

new (data+size) T(std::forward<Args>(args)...); 

если args являются основными - не - Rvalue ссылки std::string, выражение будет компилировать

new (data+size) std::string(str); //str is lvalue - calls std::string::string(const string& rhs) 

означает, конструктор копирования будет принимать место. , но, если вы используете std::move на str, код будет компилировать

new (data+size) std::string(str); //str is r-value reference, calls std::string::string(string&& rhs) 

поэтому двигайтесь семантику имеет место. это огромный прирост производительности.
Заметьте, что str является lvalue, у него есть имя, поэтому для создания r-value-reference из него вы должны использовать std::move.

в примере

vec.emplace_back("some literal"); 

код будет компилировать

new (data+size) std::string("literal"); //calls std::string::string(const char*); 

так нет временных.

третий пример - вздор. вы не можете перемещать литералы.