我有这样的代码:
#include <iostream>
#include <exception>
#include <stdexcept>
#include <string>
#include <vector>
#include <utility>
struct Foo {
Foo(std::string t):text(t){}
//destructor deleted
std::string text;
};
int main()
{
std::vector<Foo> v;
v.push_back(Foo("foo 1"));
v.push_back(Foo("foo 2"));
v.push_back(Foo("foo 3"));
for(auto& foo : v){
std::cout<<foo.text<<"\n";
}
Foo fooBack = std::move(v.back());
std::cout<<fooBack.text<<"\n";
for(auto& foo : v){
std::cout<<foo.text<<"\n";
}
}
在这种情况下,std::move()
不会窃取返回变量。有没有办法避免过度复制?
这就是结果:
foo 1
foo 2
foo 3
foo 3
foo 1
foo 2
foo 3
基于sugestions的新代码(不知道是否继续在同一个线程上问不知道这是否是我所期望的,我做这一切的原因是为了减少代码):
#include <iostream>
#include <exception>
#include <stdexcept>
#include<string>
#include<vector>
#include<utility>
struct Foo {
Foo(std::string t):text(t){
std::cout<<text<<" construct foo called \n";
}
Foo(const Foo& f){
text = f.text;
std::cout<<text<<"copy construct foo called \n";
}
Foo(Foo&& f){
text = std::move(f.text);
std::cout<<text<<"move construct foo called \n";
}
/*
~Foo() {
}
*/
std::string text;
};
int main()
{
std::vector<Foo> v;
v.emplace_back("foo 1");
v.emplace_back("foo 2");
v.emplace_back("foo 3");
for(auto&& foo : v){
std::cout<<foo.text<<"\n";
}
Foo fooBack = std::move(v.back());
v.pop_back();
std::cout<<fooBack.text<<"\n";
for(auto&& foo : v){
std::cout<<foo.text<<"\n";
}
}
新的结果来看看它的行动
foo 1 construct foo called
foo 2 construct foo called
foo 1copy construct foo called
foo 3 construct foo called
foo 1copy construct foo called
foo 2copy construct foo called
foo 1
foo 2
foo 3
foo 3move construct foo called
foo 3
foo 1
foo 2
1条答案
按热度按时间rxztt3cl1#
语句
Foo fooBack = std::move(v.back());
根本不会 * 删除 * vector中的最后一个Foo
对象,但它会 * 将该对象的内容 * 移动到fooBack
变量中,这是由于编译器为Foo
生成了一个移动构造函数。然而,原始的Foo
对象本身仍然在向量中,这就是为什么第二个for
循环仍然看到该对象的原因。对象可能不再有text
值可打印,因为fooBack
窃取了它。Live Demo
也就是说,在您的情况下,
std::string
可能正在使用“短字符串优化”(其中小字符串值保存在std::string
类本身内部的固定缓冲区中,以避免在不需要时动态分配内存),从一个std::string
“移动”到另一个std::string
只是复制该固定缓冲区的数据,保持原始的std::string
不变。这就解释了为什么你的第二个for
循环在将v.back()
“移动”到fooBack
变量后仍然在向量中显示"foo 3"
-它实际上是一个副本,而不是移动。如果你想从向量中删除最后一个
Foo
对象,你可以使用v.pop_back()
,例如:Live Demo
顺便说一句,你的
push_back()
应该使用emplace_back()
,以避免创建临时的Foo
对象,这些对象在推送过程中必须被移动: