【发布时间】:2013-09-06 20:30:38
【问题描述】:
在 C++11 中,我们被引导在某些情况下通过值传递对象,而在其他情况下通过 const-reference 传递对象。但是,此指南取决于方法的实现,而不仅仅是其接口和客户的预期用途。
当我写一个接口时,我不知道它会如何实现。编写方法签名是否有一个好的经验法则?例如——在下面的代码片段中,我应该使用Bar1还是Bar2?
class IFoo
{
public:
virtual void Bar1(std::string s) = 0;
virtual void Bar2(const std::string& s) = 0;
};
如果您同意正确的签名取决于实现,则可以停止阅读此处。这是一个例子,说明了我为什么这么认为。
在下面的例子中,我们应该按值传递字符串:
class Foo
{
std::string bar;
Foo(std::string byValue)
: bar(std::move(byValue))
{
}
};
现在我们可以在所有情况下以有效的方式实例化 Foo:
Foo foo1("Hello world"); // create once, move once
Foo foo2(s); // the programmer wants to copy s. One copy and one move
Foo foo3(std::move(t)); // the programmer does not need t anymore. No copy at all
在其他情况下,我们更喜欢通过 const 引用传递对象。例如,在以下情况下,我们不想复制/存储参数,只需使用它的方法:
void DoStuff(const std::string& byRef)
{
std::cout << byRef.length() << std::endl;
}
上述方法的所有可能用法已经尽可能高效。
更新
我相信我忘了展示 const-reference 替代方案的问题。如果上面的类Foo是这样实现的:
class Foo
{
std::string bar;
Foo(const std::string& byRef)
: bar(byRef)
{
}
};
那么我们会得到以下结果:
Foo foo1("Hello world"); // Here we would have one more copy of the string. It is less efficient.
Foo foo2(s); // One copy, like before
Foo foo3(std::move(t)); // Irrelevant here.
亚历克斯。
【问题讨论】:
-
如果要在启动方法后更改值(例如移动它),则应按值传递,否则应按引用传递。如果对象很小(小于指针大小),那么按值传递通常更有效。在任何一种情况下,使用您的 API 的人都会以相同的方式解释参数:该函数不会更改我传递给它的参数的值。
-
很明显,你永远无法肯定知道它是如何实现的(除非你始终是执行实现的人),但通常函数的名称应该提供线索:如果该函数被称为 GetStringLength ,那么您可以确定它不会复制参数:P
-
@MadScienceDreams,你是对的。但是,我问的是函数希望从调用者的角度对其参数进行只读访问的情况(在内部它可能会移动一个按值对象,但调用者不知道这一点)。从效率的角度来看,实现这些功能的“正确”方式是不同的,具体取决于实现。我要问的是,是否有一些通用的方法可以编写既高效又不依赖于实现的纯虚函数。
-
@stijn 你可能是对的,但我没有什么技巧可以做的吗?有模板的东西?也许还有别的?
-
假设我不想修改传递的变量并且它不是基本数据类型,我总是通过 const 引用传递。如果我需要在函数中修改它,只需在本地复制引用即可。
标签: c++ c++11 move-semantics pure-virtual