【问题标题】:Is this a valid use of const_cast?这是对 const_cast 的有效使用吗?
【发布时间】:2015-04-20 18:51:17
【问题描述】:

在示例代码中,调用message() 永远不会影响类的内容,所以我希望方法是const。但我不希望返回值也为const,所以如下使用const_cast 是否安全?还是有更好的解决方案?

编辑:对不起..所以n_ 是一个指针!

EDIT2:我终于设法正确地重现了这个问题。如果n_int n[100] 中的数组怎么办?然后我确实看到了没有const_cast 的问题。

class A
{
private:
    int n_[10];

public:
    /* ... */

    int* n() const
    {
        return const_cast<int*>(n_);
    }
};

【问题讨论】:

  • 可以,但没必要。您没有返回引用,因此调用者无法通过调用 n() 来修改 n_
  • 当前代码正试图将int* 作为int 返回。
  • 现在你允许我这样做了:const A a; int* p = a.n(); p[0] = 2;。所以不,这根本不安全。

标签: c++ constants const-cast


【解决方案1】:

返回一个类型(不是一个引用)将生成一个你返回的对象的副本。这样就不需要强制转换了,可以修改副本而不影响原件。如果删除const_cast,代码将编译干净。

编辑:根据对问题的最新编辑,我会说这是对const_cast 的滥用。 C++ 遵循的原则是const 成员函数不仅不应更改对象本身,而且不应返回任何可用于在函数之外进行更改的内容。通过返回指向成员变量的非常量指针,您违反了这一原则。

【讨论】:

  • 在该函数的上下文中,n_ 不是隐含的const
  • 你能看到我的编辑吗?我在原帖中犯了一个大错误。
  • @tadman 是的,但您可以毫无问题地复制 const 变量。
  • 对。我只是在验证 const_cast 是多余的,因为它已经被认为是 const
  • @xiver77 是的,这对问题有很大的不同。
【解决方案2】:

不,这不是const_cast 的有效用法。

您的函数不是修改数组,而是授予调用者修改数组的权限。因此,它本身应该拥有这些权利。你不能让别人访问你自己无权访问的东西。所以方法不应该是 const,那么 const 转换就没有必要了。

您可能还需要函数的 const 版本,它返回 const int*。这与例如std::vector::operator[] 的原理相同。即使运算符不修改向量,它也授予修改向量的访问权限,因此它不是 const 函数。 (但也有一个 const 重载版本,它返回一个 const 引用,从而不授予修改向量的权利)

【讨论】:

    【解决方案3】:

    您可以原样返回n_

    int n() const
    {
        return n_;
    }
    

    【讨论】:

      【解决方案4】:

      不需要使用演员表。在函数中,this-&gt;n_ 是一个const 指针,它不指向const int

      int* n() const
      {
          // No need for a cast.
          return n_;
      }
      

      const 函数返回const int* 更有意义。你不想要这样的东西:

      const A a;
      a.n()[0] = 10;
      

      这颠覆了对象的const-ness。您可以使用以下方法防止这种情况:

      const int* n() const
      {
          // No need for a cast either.
          return n_;
      }
      

      【讨论】:

        【解决方案5】:

        一般来说,用const_cast&lt;&gt;T const 转换为T 几乎总是不必要的。这是因为常量对象正在被转换为非常量临时对象,而这可以在不进行强制转换的情况下安全地完成。

        int const n;   // n is a constant int
        int x = n;     // perfectly safe
        

        即使T 是指针类型也是如此。

        int * const n; // n is a constant pointer to an int
        int * x = n;   // perfectly safe
        

        但是,如果将const 关键字移到前面,则不再使指针类型成为常量,而是使指向的类型成为常量。因此,对于我们上面的示例:

        const int * n; // n is a pointer to a constant int
        int * x = n    // error, x is a pointer to an int
        

        您可以看到x 指向的对象与n 指向的对象不同,因此初始化将失败。在这种情况下,初始化需要const_cast&lt;&gt;:

        int * x = const_cast<int *>(n);
                       // cast away the const-ness that n is pointing to
        

        只有在您知道n 实际上是可修改的(如果指针指向实际的只读内存时可能不是),或者您知道x 的用户实际上不会尝试时,您才应该这样做修改n指向的内容。


        对于您的示例,您似乎认为您的 const 方法应该返回指向您的对象持有的数据的指针,以便调用者可以修改数据。也就是说,由于n() 方法被声明为const,这意味着被访问的对象的内容应该被认为是常量。因此,n_ 是一个常量int 的数组,它会衰减为一个指向常量int 的指针,但您想返回一个指向int 的指针。

        如果您希望 n_ 可修改,无论对象是否被视为常量,您都可以使用 mutable 声明该意图。即使包含对象是const,这也会使n_ 被视为非常量,因此不需要const_cast

        class A
        {
        private:
            mutable int n_[10];
        
        public:
            /* ... */
        
            int* n() const
            {
                return n_;
            }
        };
        

        【讨论】:

          猜你喜欢
          • 2010-12-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-02-22
          • 1970-01-01
          • 2011-01-10
          • 1970-01-01
          相关资源
          最近更新 更多