如何改进 std::vector 参数传递(移动语义?)
How to improve std::vector parameter passing (move semantics?)
似乎我无法完全理解移动语义:我想从外部函数填充一个std::vector
(class的成员)。目前,我有类似的东西:
void fillVector(MyClass & myclass) {
std::vector<int> vec;
/* Filling vec */
// ...
myclass.setVector(vec);
}
class MyClass {
public:
setVector(const std::vector<int> & v) { v_ = v;}
private:
std::vector<int> v_;
};
int main() {
MyClass myclass;
fillVector(myclass);
/* Use myclass.v_ somehow */.
}
我有这个代码很长时间了,它工作得很好。现在,我无法理解它是如何工作的,因为我正在分配对将被销毁的向量的引用。我的问题是:
- 这段代码如何工作?
- 实施
fillVector
和 MyClass::setVector()
的最佳方法是什么?我认为这可以通过移动语义来完成,但我不知道该怎么做。
谢谢!
为什么代码有效:
vec
的范围是 fillVector
的正文。在整个范围内,vec
是完全有效的。这包括对 setVector
的调用。 v
(setVector
的参数)是绑定到 vec
的引用。 setVector
的主体将向量 vec
(访问方式为 v
)的内容 复制到 v_
中。那是数据的实际副本,没有引用分配。只有在 setVector
结束后 fillVector
才结束,此时 vec
被销毁。但是已经复制了,所以一切都很好。
如何使用移动语义:
您可以提供额外的 setVector
重载,它将采用右值引用:
class MyClass {
public:
// ...
void setVector(std::vector<int> &&v) { v_ = std::move(v); }
// ...
};
然后,将vec
移动到setVector
:
void fillVector(MyClass & myclass) {
std::vector<int> vec;
/* Filling vec */
// ...
myclass.setVector(std::move(vec));
}
这将调用右值重载而不是左值重载,数据将被移动,而不是被复制。
然而,也许更好的接口是重构 fillVector
以便它 returns 按值自动使用移动语义的向量:
std::vector<int> fillVector() {
std::vector<int> vec;
/* Filling vec */
// ...
return vec; // Note that a move automatically happens here, or even NRVO
}
int main() {
MyClass myclass;
myclass.setVector(fillVector());
/* Use myclass.v_ somehow */.
}
vector::operator= 分配内容,而不仅仅是 link 现有项目。当你执行 v_ = v 时,v_ 会得到 v 中所有内容的新副本。一旦 v 被销毁,v_ 中的项目仍然存在。
一个简单的方法来测试它并查看它的实际效果是更改 v_[i] 中的一项并查看然后打印出 v[i] 和 v_[i]。他们会有所不同。
我没有发现您对 setVector 和 fillVector 的实施有任何问题。您有什么特别想要实现的目标吗?
似乎我无法完全理解移动语义:我想从外部函数填充一个std::vector
(class的成员)。目前,我有类似的东西:
void fillVector(MyClass & myclass) {
std::vector<int> vec;
/* Filling vec */
// ...
myclass.setVector(vec);
}
class MyClass {
public:
setVector(const std::vector<int> & v) { v_ = v;}
private:
std::vector<int> v_;
};
int main() {
MyClass myclass;
fillVector(myclass);
/* Use myclass.v_ somehow */.
}
我有这个代码很长时间了,它工作得很好。现在,我无法理解它是如何工作的,因为我正在分配对将被销毁的向量的引用。我的问题是:
- 这段代码如何工作?
- 实施
fillVector
和MyClass::setVector()
的最佳方法是什么?我认为这可以通过移动语义来完成,但我不知道该怎么做。
谢谢!
为什么代码有效:
vec
的范围是 fillVector
的正文。在整个范围内,vec
是完全有效的。这包括对 setVector
的调用。 v
(setVector
的参数)是绑定到 vec
的引用。 setVector
的主体将向量 vec
(访问方式为 v
)的内容 复制到 v_
中。那是数据的实际副本,没有引用分配。只有在 setVector
结束后 fillVector
才结束,此时 vec
被销毁。但是已经复制了,所以一切都很好。
如何使用移动语义:
您可以提供额外的 setVector
重载,它将采用右值引用:
class MyClass {
public:
// ...
void setVector(std::vector<int> &&v) { v_ = std::move(v); }
// ...
};
然后,将vec
移动到setVector
:
void fillVector(MyClass & myclass) {
std::vector<int> vec;
/* Filling vec */
// ...
myclass.setVector(std::move(vec));
}
这将调用右值重载而不是左值重载,数据将被移动,而不是被复制。
然而,也许更好的接口是重构 fillVector
以便它 returns 按值自动使用移动语义的向量:
std::vector<int> fillVector() {
std::vector<int> vec;
/* Filling vec */
// ...
return vec; // Note that a move automatically happens here, or even NRVO
}
int main() {
MyClass myclass;
myclass.setVector(fillVector());
/* Use myclass.v_ somehow */.
}
vector::operator= 分配内容,而不仅仅是 link 现有项目。当你执行 v_ = v 时,v_ 会得到 v 中所有内容的新副本。一旦 v 被销毁,v_ 中的项目仍然存在。
一个简单的方法来测试它并查看它的实际效果是更改 v_[i] 中的一项并查看然后打印出 v[i] 和 v_[i]。他们会有所不同。
我没有发现您对 setVector 和 fillVector 的实施有任何问题。您有什么特别想要实现的目标吗?