C++11中返回const值类型对移动语义的影响

3

我不太清楚在C++11中返回const值对移动语义的影响。

这两个返回数据成员的函数有什么区别吗?在C++11中const还是多余的吗?

int GetValueA() { return mValueA; }
const int GetValueB() { return mValueB; }

这些函数怎么办?
int GetValuesAB() { return mValueA + mValueB; }
const int GetValuesCD() { return mValueC + mValueD; }

8
"int" 是一种原始数据类型,所以没有区别。 - Cheers and hth. - Alf
@Alf,您是否意味着对于例如std::string,会有所不同?如果是这样,具体是哪些方面的不同? - Walter
@Walter:如果返回值不是const,你可以使用字符串 foo() += "bar"; - Kerrek SB
1
是的,我本来想说在这种情况下不是这样的,但返回一个非基本类型的const会做很多事情...除了所有的const限制之外,在c++11中它实际上会禁用rvalue移动构造函数 - IdeaHat
@KerrekSB 嗯,也许吧,但那不是一个明智的指令。由 foo() 返回的对象在 += 操作后被销毁。因此,只有 += 的副作用没有被遗忘... - Walter
显示剩余3条评论
1个回答

6
调用返回值的函数表达式是prvalue。然而,非类和非数组类型(§5/6)没有常量prvalue:
如果prvalue最初具有“cv T”类型,其中T是cv未限定的非类、非数组类型,则在进一步分析之前将表达式的类型调整为T。
这意味着你的两个函数定义没有区别。无论它返回const int还是int都不相关,因为表达式从未是const。
然而,当你返回一个类类型时就会有所不同。请看以下示例:
struct foo
{
  void bar() { std::cout << "Hello" << std::endl; }
};

foo get_foo();

现在,如果我们调用get_foo(),我们会得到一个临时的foo对象。这个prvalue不是const,我们可以在它上面调用非const成员函数,所以我们可以愉快地执行get_foo().bar()。然而,我们可以这样改变get_foo的声明:
const foo get_foo();

现在,表达式get_foo()是一个const的prvalue(因为它是一个类类型),我们不能再调用由它返回的临时对象上的bar

然而,对于非类类型来说谈论移动语义是没有意义的,因为int类型永远不会被移动。如果你返回一个const的类类型,那么也不能从中移动任何东西,因为它是const的。为了证明:

foo get_foo();
foo f(get_foo()); // Will call the move constructor

const foo get_foo();
foo f(get_foo()); // Will call the copy constructor

这是因为const prvalue无法绑定到非const rvalue引用,而移动构造函数需要该类型作为其参数。

如果void bar()变为void bar() const,我们能否在临时对象上调用它? - sourcenouveau
@M.Dudley 是的,你需要这样做。我刚刚添加了一些关于移动语义的内容,因为我在原始答案中忘记了它。 - Joseph Mansfield
foo(const foo&& f) 移动构造函数来拯救?(就像有不止一个拷贝构造函数一样...) - Yakk - Adam Nevraumont
@Yakk 如果 fconst 的话,你就无法从中移动了。 - Joseph Mansfield
结构体 foo { mutable std::unique_ptr<int> ptr; foo(const foo&& o):ptr(std::move(o.ptr)) {};};(注:有些人可能会有不同的意见。 :)) - Yakk - Adam Nevraumont
@JosephMansfield根据移动对象的最终状态要求,@yakk的想法是可行的,只要它没有发生任何更改。 - Don Slowik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接