11

我不记得传递 STL 容器是否会生成容器的副本,或者只是另一个别名。如果我有几个容器:

std::unordered_map<int,std::string> _hashStuff;
std::vector<char> _characterStuff;

我想将这些变量传递给一个函数,我可以这样创建函数吗:

void SomeClass::someFunction(std::vector<char> characterStuff);

或者这会复制unordered_map/vector吗?我想我可能需要使用shared_ptr.

void SomeClass::someFunction(std::shared_ptr<std::vector<char>> characterStuff);
4

3 回答 3

12

这取决于。如果您将输入中的左值传递给您的函数(实际上,如果您传递的东西有一个名称,可以应用地址运算符 & ),那么您的类的复制构造函数将被调用。

void foo(vector<char> v)
{
    ...
}

int bar()
{
    vector<char> myChars = { 'a', 'b', 'c' };
    foo(myChars); // myChars gets COPIED
}

如果您要传递一个右值(粗略地说,一些没有名称且不能应用地址运算符 & 的东西)并且该类有一个移动构造函数,那么该对象将被移动(不是,请注意,与创建“别名”相同,而是将对象的内脏转移到新的骨架中,使之前的骨架无用)。

在下面的调用foo()中, 的结果make_vector()是一个rvalue。因此,它返回的对象在输入时被移动foo()vector即将调用移动构造函数):

void foo(vector<char> v);
{
    ...
}

vector<char> make_vector() 
{ 
    ...
};

int bar()
{
    foo(make_vector()); // myChars gets MOVED
}

一些 STL 类具有移动构造函数但没有复制构造函数,因为它们本质上是不可复制的(例如,unique_ptr)。unique_ptr当你将它传递给一个函数时,你不会得到它的副本。

即使对于那些确实具有复制构造函数的类,您仍然可以通过使用该std::move函数将参数从左值更改为右值来强制移动语义,但同样不会创建别名,它只是转移对象的所有权到您正在调用的功能。这意味着您将无法对原始对象执行任何其他操作,除非重新分配给它另一个值或将其销毁。

例如:

void foo(vector<char> v)
{
    ...
}

vector<char> make_vector() 
{ 
    ...
};

int bar()
{
    vector<char> myChars = { 'a', 'b', 'c' };
    foo(move(myChars)); // myChars gets MOVED
    cout << myChars.size(); // ERROR! object myChars has been moved
    myChars = make_vector(); // OK, you can assign another vector to myChars
}

如果您发现左值和右值引用的整个主题并且移动语义晦涩难懂,那是非常可以理解的。我个人觉得这个教程很有帮助:

http://thbecker.net/articles/rvalue_references/section_01.html

您应该也可以在http://www.isocpp.org或 YouTube 上找到一些信息(查找 Scott Meyers 的研讨会)。

于 2012-12-28T20:04:08.733 回答
6

是的,它会复制向量,因为您是按值传递的。按值传递总是会复制或移动(在某些情况下可能会被省略,但在您的情况下不会)。如果你想在函数内部和外部引用相同的向量,你可以通过引用传递它。将您的功能更改为:

void SomeClass::someFunction(std::vector<char>& characterStuff);

该类型std::vector<char>&是一个引用类型,“reference to std::vector<char>”。该名称characterStuff将作为 引用的对象的别名_characterStuff

于 2012-12-28T18:53:30.550 回答
5

C++ 是基于值的:当按值传递对象时,您将获得独立的副本。如果您不想获得副本,则可以使用参考或const参考,而不是:

void SomeClass::someFunction(std::vector<char>& changable) { ... }
void SomeClass::otherFunction(std::vector<char> const& immutable) { ... }

当被调用的函数不应该能够改变参数但你不想创建对象的副本时,你会想通过const&. 通常,我不会使用类似 a 的东西std::shared_ptr<T>。这种类型的用途当然不是在调用函数时防止复制。

于 2012-12-28T18:57:52.870 回答