【问题标题】:C++: Prevent changing pointer's value in const functionC++:防止在 const 函数中更改指针的值
【发布时间】:2017-12-21 09:28:38
【问题描述】:

采用这个虚拟结构:

struct foo
{
    int* pI;
    void bar() const
    {
        int* ptrToI = pI; // I want this to require 'const int*'
        *ptrToI = 5; // I want this to fail
    }
}__test__;

如何设计这个结构来防止我改变 pI 指向的值?

【问题讨论】:

  • const int* pI; ?究竟是什么问题?
  • 与您的问题无关,但不要使用带有两个前导下划线的符号(例如__test__),这些符号在所有范围内都是保留的。请看this old question and its answers for more information
  • 该解决方案被提议包含在C++标准中:propagate_const
  • 如果您不需要 foo 可分配,并且不需要重置 pI 所指的内容,那么从技术上讲,您可以使用 C++ 引用而不是 C++ 指针。否则,您可能会使用自定义智能指针,正如@lopital 在答案中所建议的那样。但很有可能您正在重新发明std::stringstd::vector 之类的东西,然后使用标准容器。

标签: c++ pointers constants


【解决方案1】:

您可以使用自定义smart pointer 来隐藏底层指针:

template <typename T>
struct ptr_t
{
private:
    T *ptr;
public:
    //Constructors and assignment operators
    ptr_t(): ptr(nullptr) {}
    ptr_t(T* p): ptr(p) {}
    ptr_t(const ptr_t &other): ptr(other.ptr) {}
    ptr_t& operator=(T* p) {this->ptr=p;return *this;}
    ptr_t& operator=(const ptr_t &other) {this->ptr=other.ptr; return *this;}

    //Note that the smart pointers included in the standard returns non-const pointers
    //That is why you need to define a custom smart pointer, which forces the const pointer return in the const version of the operators.
    const T* operator->() const {return ptr;}
    T* operator->() {return ptr;}
    const T& operator&() const {return *ptr;}
    T& operator&() {return *ptr;}

    operator const T*() const {return ptr;}
    operator T*() {return ptr;}
};

struct foo2
{
    ptr_t<int> pI;
    void nonconst_bar()
    {
        int* ptrToI = pI; // Now success, since not const
        *ptrToI = 5;
    }

    void failing_bar() const
    {
        //int* ptrToI = pI; // This fails
        //*pI = 5; // This also fails
    }

    void success_bar() const
    {
        const int* ptrToI = pI;
        //*ptrToI = 5; // This is not possible anymore
    }
};

【讨论】:

  • 我在链表类中使用它。你的解决方案非常适合我的西装!
【解决方案2】:

除非您可以创建成员 const int*,否则您可以使用继承来隐藏成员,使其不成为子类,并在基类中提供一个 protected 函数,该函数会产生一个 const int* 指针:

class base_foo
{
    int* pI;
protected:
    const int* get_pI(){return pI;}
};

struct foo : base_foo
{
    int* ptrToI = get_pI(); // will fail due to attempted conversion to int*
    /* and so on*/

另请注意,任何包含两个连续下划线的标记都是保留的,因此,正式地,您的程序的行为是未定义的:重命名 __test__

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    • 2019-03-22
    相关资源
    最近更新 更多