【问题标题】:const overloading and shared pointersconst 重载和共享指针
【发布时间】:2016-11-16 18:07:00
【问题描述】:

试图更好地掌握围绕 const 重载的规则。考虑以下代码 -

MyClass.h

class MyClass
{
public:
    MyClass();
    ~MyClass();
};

MyClass.cpp

#include "MyClass.h"
MyClass::MyClass() 
{
}
MyClass::~MyClass()
{
}

main.cpp

#include <iostream>
#include "MyClass.h"
#include <memory>
using namespace std;

/*
void test_function(MyClass& test)
{
    cout << "ref to non const" << endl;
}
*/
void test_function(const MyClass& test)
{
    cout << "ref to const" << endl;
}
/*
void test_shared_ptr( shared_ptr<MyClass>& test)
{
    cout << "ref to non const shared ptr to non const" << endl;
}

void test_shared_ptr ( const shared_ptr<MyClass>& test)
{
    cout << "ref to const shared ptr to non const" << endl;
}
*/
void test_shared_ptr (const shared_ptr<const MyClass>& test)
{
    cout << "ref to const shared ptr to const" << endl;
}

int main()
{
    MyClass non_const_my_class;
    test_function(non_const_my_class);
    const MyClass const_my_class;
    test_function(const_my_class);

    shared_ptr<MyClass> non_const_ptr_to_non_const = make_shared<MyClass>                (MyClass());
    test_shared_ptr(non_const_ptr_to_non_const);

    const shared_ptr<MyClass> const_ptr_to_non_const = make_shared<MyClass>(MyClass());
    test_shared_ptr(const_ptr_to_non_const);

    const shared_ptr< const MyClass> const_ptr_to_const = make_shared< const MyClass>(MyClass());
    test_shared_ptr(const_ptr_to_const);

    int pause;
    cin >> pause;
    return 0;
}

注释掉方法后的输出是:

ref to const
ref to const
ref to const shared ptr to const
ref to const shared ptr to const
ref to const shared ptr to const

这个输出是我所期望的,但是我在一些围绕这种类型的 const 重载的代码上遇到了一个潜在的错误。真的只是想对以下陈述进行一些验证:

  1. 始终可以将非常量数据作为对 const 的引用传递给函数,只要该函数不试图违反其参数的 const 性。这会导致编译错误。
  2. 永远不行,因为它会导致编译错误,将 const 数据作为对非 const 的引用传递给函数。这将违反数据的常量性。

最后一个问题——

在什么情况下您可能需要如下代码?在我上面的测试代码中,将非 const 数据作为 const 引用传递给函数是非常好的,那么我为什么需要像这样执行 const_cast 呢?

void test_const_cast(const MyClass & test)
{
    //Do something
}

void test_const_cast( MyClass & test)
{
    test_const_cast(const_cast<MyClass const &>(test));
}

【问题讨论】:

    标签: c++ c++11 pointers c++14


    【解决方案1】:

    声明 1:对于 C++98 来说接近,甚至比对于 C++11 更接近。在 C++11 中,当涉及到标准库时,增加了一个要求,即 const 成员函数不引入数据竞争。见http://channel9.msdn.com/posts/C-and-Beyond-2012-Herb-Sutter-You-dont-know-blank-and-blank。除了具有类型实例的极端情况之外,该类型实例具有引入数据竞争的 const 成员函数,而非常量重载则没有,将可变左值传递给采用对 const 的引用的函数是可以的。 即使该函数确实违反了其参数的常量性(通过使用const_cast&lt;&gt;())。

    声明 2: 可以将 const 数据作为对非 const 的引用传递,提供函数实际上不会更改其参数引用的对象。这是const_cast&lt;&gt;() 的主要预期用例。

    额外问题:使用const_cast&lt;&gt;()添加 const 的代码主要在重载函数的返回值不是void 时很有用。例如,标准库为std::vector&lt;T /* technically more type paraeters here */&gt; 提供了非成员begin()end() 函数,例如采用const vector&lt;int&gt;&amp; 的重载返回vector&lt;int&gt;::const_iterator,但采用vector&lt;int&gt;&amp; 的重载返回vector&lt;int&gt;::iterator .如果您想要const_iterator 而不仅仅是iterator,并且不想麻烦地将iterator 转换为const_iterator,您可以这样做。这就是 C++17 引入 as_const() http://en.cppreference.com/w/cpp/utility/as_const 的原因,以使其更容易且无需使用可怕的 const_cast&lt;&gt;()

    【讨论】:

      【解决方案2】:

      将非常量数据作为对 const 的引用传递给函数总是可以的,只要该函数不试图违反其参数的 const 性。这会导致编译错误。

      并非总是如此。 C++ 不喜欢传递使用常量模板化的类型。考虑以下代码:

      #include <vector>
      using std::vector;
      
      void test(const vector<const int> & b) { }
      
      int main() {
        vector<int> a;
        test(a);
      }
      

      这里,aint 的向量,test 接受 const 的向量 const inttest 的约束本质上是一个承诺,它既不会修改b 也不会修改其中的元素;直观地说,它根本不应该对a 施加任何限制。然而代码不会编译。例如,在 clang 中,您会收到以下错误:

      test_template.cxx:11:3: error: no matching function for call to 'test'
        test(a);
        ^~~~
      test_template.cxx:5:6: note: candidate function not viable: no known conversion
            from 'vector<int>' to 'const vector<const int>' for 1st argument
          void test(const vector<const int> & a) { }
           ^
      

      删除vector 前面的const 实际上,它确实可以编译(至少在clang 上)。所以const 和你总结的不太一样。

      【讨论】:

      • 这不太正确。 模板参数 无法转换。 The object can。你的结论似乎是正确的,但我认为你有一个错字。如果你把const前面的int去掉,那就对了。
      • 在 Visual Studio 中 - “C++ 标准库禁止 const 元素的容器...”
      • @erip 从哪个int 的前面去掉const?我不确定为什么需要进行更改,但我同意您的说明,即 template 参数 不能转换,而 object 可以。我想我的“数据”概念更广泛一些。
      • @LBaelish 奇怪,因为 clang 一直接受包含 const int 的向量。它是否提供了准确的参考?
      【解决方案3】:

      这个问题的答案似乎是它只是依赖于编译器。可以使用 Visual Studio 编译器将指向 const 数据的非 const 指针传递给一个函数,该函数将指向 const 数据的 const 指针作为参数,但不能使用 gcc。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-05-14
        • 2012-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多