为什么我构造的临时对象const不可变?

时间:2015-11-06 16:28:29

标签: c++ c++11 move-semantics rvalue

我有一个类K,我正在调用函数test中构建一个对象。所以我相信构造的K被称为 r-value 。 (这是真的吗?)

但我很困惑,并且担心K对象显然是 const ,而不是 mutable 。我不想要它。

简单测试程序:

#include <iostream>

class K {};

std::string test (K &k) {return "mutable";}

std::string test (const K &k) {return "const";}

int main (int argc, const char **argv) {
  std::cerr << "K constructed for function argument is " << test(K{}) << "\n";
  K k;
  std::cerr << "K constructed for local variable is " << test(k) << "\n";
}

输出:

  

为函数参数构造的K是const

     

为局部变量构造的K是可变的

请注意,当我动态创建K作为函数参数传递时,我得到一个const对象,而当我创建它作为局部变量时,我得到一个可变的。

出于我的目的,我真的希望两种情况都有可变性。你能告诉我怎么做,或者说服我为什么不应该这样做?

3 个答案:

答案 0 :(得分:3)

引用无法绑定到临时对象,但const T&可以绑定。由于选择了K{}是临时std::string test (const K &k) {return "const";}

如果你真的想要修改临时版,那么可以使用和r值引用

std::string test (K &&k) {return "r-value";}

Live Example

答案 1 :(得分:1)

在标准C ++中,您无法将临时对象绑定到非const引用。但是,您可以将其绑定到右值引用。 MSVC的用户享受将临时绑定到非const引用的“扩展”。

答案 2 :(得分:0)

看起来你的语法在l值引用和r值引用之间混淆了。

K& k:这是一个非const l值引用。它通常只能绑定到具有名称的变量。此语法暗示(通常)您正在接受k修改函数内部,这样k也是函数的输出。用临时做这件事实际上没有意义,因为临时性将会消失。对于变量(除了深奥的编译器扩展)之外,它才真正有意义。

const K& k:const引用。这可以绑定到l或r值。这意味着您在函数中使用k,但(通常)不需要复制它,当然也不会修改它。这是安全的,因为你无法修改临时(因此没有隐含的假设它将在以后使用),并且临时将在函数的生命周期中存在。

K&& k:这是一个r值参考。它意味着移动语义,即使用k的函数只接受一个临时值(或一个随std::move移动的值),它将取得所述临时值的所有权

在实践中,我个人发现使用r值参考的唯一必要(或者甚至是适当的)是:

  1. 容器的类构造函数。这些应该有一个移动构造函数/移动分配器,以便在使用临时值创建时它们可以获得所有权。
  2. 转发功能。即包装函数,只调用低级类函数。如果这些低级类函数支持r值,则可以使用通用引用来确保支持不会搞砸。
  3. 你的第一直觉应该是避免函数调用中的r值。

    另一方面,如果您实际尝试将临时绑定到非const引用,我认为这个问题/答案可以更好地解释为什么不允许它: How come a non-const reference cannot bind to a temporary object?