【问题标题】:Temporary Objects and pass by (const/non-const) `value`临时对象并通过 (const/non-const) `value`
【发布时间】:2013-08-20 18:05:00
【问题描述】:

临时对象的生命周期持续到使用without references时创建它的表达式的完整长度。

考虑以下几点:

 class My
 {
   int i;
   public:
     void increment()
     {
       i++;
     }
 };

 My withOutConst()
 {
   return My();
 }

 const My withConst()
 {
   return My();
 }

 int main()
 {
   My ob;
   withOutConst().increment();  // Case 1
   withConst().increment();     // Case 2

   return 0;
 }

据我了解,编译器会创建一个 temporary 对象(const My 类型)来保存上述情况下的返回值。 而且,我正在尝试修改临时对象。

(1)编译正常

(2) 导致编译时错误,错误为:

error: passing 'const My' as 'this' argument of void My::increment() discards qualifiers

这意味着基本上thisMy 类型,而不是const My,因为它是为non-const 函数调用的。

我的问题:

我正在尝试通过调用non-const 成员函数来修改const My 类型的临时对象。

那么为什么我在 case(1) 中没有得到相同的错误,因为在这两种情况下我都在对 const My 类型的对象进行操作。

我知道这与函数的return type 有关,但我无法完全理解,因为最后它归结为函数(void My::increment()),它试图修改const My 类型的临时变量两种情况。

【问题讨论】:

  • 很久没用C++做点什么了,My ob;有什么作用呢?
  • 在情况 1 中,您的临时地址不是 const。所以你可以在它上面调用非常量方法。案例 2 中的情况并非如此。
  • 这里要记住的重要一点是,您创建了两个函数,它们基本上分别创建对象My xconst My y。所以,真的,你的My ob 没有实际用途。很可能编译器只是将其优化为我上面提到的内容。

标签: c++ temporary-objects


【解决方案1】:

临时有一个类型,该类型可以是 const,也可以是非常量。您只能在非常量对象上调用非常量成员函数。 withOutConst() 产生一个 My 类型的临时,withConst() 产生一个 const My 类型的临时。

也许你有一个误解,即临时总是const?如果是这样,那就错了。

【讨论】:

  • 但我正在查看thinking in C++,它说编译器会自动生成临时文件const。这让我想到了这个问题。
  • @UchiaItachi:这本书可以这么说,但你已经注意到了,临时的不是const
  • 是的,我同意,因为它适用于上述情况。但是,考虑到我还有一个函数void change(My &ref),我把它称为change(withOutConst()),我在这里也遇到了一个错误,但是如果函数是void change(const My &ref),它就会消失,这并不意味着临时是const类型?
  • @UchiaItachi:我明白了。问题很好,答案就是这样:)
  • @UchiaItachi:不,不代表临时是const。对withOutConst()withConst() 的调用都是rvalue 表达式,const My&My& 都是lvalue 引用。您不能将(可修改的)lvalue 引用绑定到 rvalue。语言中有一个特殊规则允许通过延长 rvalue 以匹配绑定引用的生命周期。但这是绑定引用的特定规则。
【解决方案2】:

那么为什么我在 case(1) 中没有得到相同的错误,因为在这两种情况下我都在操作 const My 类型的对象。

这根本不是真的。

 My withOutConst()
 {
   return My();
 }

 const My withConst()
 {
   return My();
 }

withOutConst 返回My 类型的对象,而withConst() 返回const My 类型的对象。尽管在这两种情况下您都将它们用作临时对象,但它们的基础类型 Myconst My 与函数签名中的编码完全相同。

【讨论】:

    【解决方案3】:
    1. 返回一个临时的非常量对象,在其上调用函数,然后超出范围。
    2. 返回一个临时 const 对象,该对象不允许调用非常量函数。

    临时对象不必是 const。

    【讨论】:

      【解决方案4】:

      据我了解,编译器会创建一个临时对象(const My 类型)来保存上述情况下的返回值。

      没有。 withOutConst() 的返回值不是const,因为你没有声明它const。观察到的行为由此而来。

      您可能会将const 与作为右值 混淆。在许多情况下,一个 rvalue 是不能被修改的;但是您可以在其中调用非常量成员函数。

      【讨论】:

        【解决方案5】:

        如果这是您尝试在更复杂的代码库中执行的操作的简化版本,您仍想在 const 对象上使用某种计数器,那么您需要标记“i”变量作为“可变”。像这样:

        class My
        {
           mutable int i;
        public:
           void increment()
           {
              i++;
           }
        };
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-17
          • 2015-01-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多