【问题标题】:Ensuring constness of member variable of const pointer保证 const 指针成员变量的 const 性
【发布时间】:2015-09-03 08:40:23
【问题描述】:

为什么这段代码可以顺利编译?

class myvector
{
public:
    myvector()
    {
        begin = new double[10];
        end = begin+10;
    }
    ~myvector()
    {
        delete[] begin;
    }

    double *begin;
    double *end;
};

class VectorWorker
{
public:
    VectorWorker(){}
    void doWork(const myvector *v)
    {
        for (int i=0;i<10;i++)
            v->begin[i] = i; // I don't want this to compile! I'd prefer compiler says me I can't modify v->begin
    }

    void doWork2(const myvector *const v) const
    {
        for (int i=0;i<10;i++)
            v->begin[i] = i; // I don't want this to compile!  I'd prefer compiler says me I can't modify v->begin
    }

    void doWork3(const myvector &v)
    {
        for (int i=0;i<10;i++)
            v.begin[i] = i; // I don't want this to compile!  I'd prefer compiler says me I can't modify v->begin
    }
};

int main(int, char*[])
{

    myvector x;
    VectorWorker work;
    work.doWork(&x);

    work.doWork2(&x);
    work.doWork3(x);

    return 0;
}

我希望将const myvector *v 传递给VectorWorker::doWork 方法应该确保myvector 中的变量保持不变,但实际上它们已被修改。如何确定doWork方法允许只读操作?

实际上我无法将double *begin 和double *end 变量修改为const double *,因为它们来自第三方库。但是,即使通过const pointer,我如何确保它们在通过它们所属的类的实例时保持原样?

代码在 coliru 中可用:http://coliru.stacked-crooked.com/a/bb43fbebebdb5872

【问题讨论】:

  • 修改v.begin 和修改v.begin 指向的内容是完全不同的事情。通常的解决方案是,如果对象是const,则只公开一个不可修改的接口,但如果您无法控制myvector 的定义,则您无能为力。
  • [OT]:你不尊重 myvector 的 5 规则。

标签: c++ pointers compiler-errors constants


【解决方案1】:

使用访问器:

class myvector
{
public:
    //previous code

    const double* get_begin() const { return begin; }
    const double* get_end() const { return end; }
    double* get_begin() { return begin; }
    double* get_end() { return begin; }
private:
    double *begin;
    double *end;
};

【讨论】:

    【解决方案2】:

    所以你不能用双指针来做到这一点。如果您真的希望它“正常工作”,那么您可以创建一个自定义 DoublePtr 类型:

    class DoublePtr
    {
    public:
        DoublePtr() { _ptr = 0; }
        DoublePtr(double* ptr) { _ptr = ptr; }
        //index operators provide lookups
        double& operator[](int pos) {
            return _ptr[pos];
        }
        const double& operator[](int pos) const {
            return _ptr[pos];
        }
    
        //casts for backward compatibility
        operator double*() {
            return _ptr;
        }
        operator const double*() const {
            return _ptr;
        }
    private:
        double* _ptr;
    };
    
    class myvector
    {
    public:
        myvector()
        {
            buffer = new double[10];
            begin = DoublePtr(buffer);
            end = DoublePtr(buffer+10);
        }
        ~myvector()
        {
            delete[] begin;
        }
    
        DoublePtr begin;
        DoublePtr end;
    private:
        double* buffer;
    };
    

    那么 VectorWorker 代码根本不需要更改。

    说了这么多 - 如果你可以使用它们,访问器似乎是一个更好的方法。

    【讨论】:

      【解决方案3】:

      const 不是传递的;虽然指针本身将是 const(您不能设置“开始”),但它指向的值不是。

      因此,如果不修改 myvector(您说这不是一个选项)或仅通过仅提供 const 访问的包装器访问它,您将无法获得此行为。

      这不是一个理想的解决方案 - 最好修复 myvector 可憎(这是来自哪个库?)。

      例如

      class myvectorconst
      {
      private:
          myvector* vec_;
      public:
          myvectorconst(myvector* vec) : vec_(vec) {}
          double const* begin() const { return vec_->begin; }
      };
      
      class VectorWorker
      {
      public:
          VectorWorker(){}
          void doWork(const myvectorconst& v)
          {
              for (int i=0;i<10;i++)
                  v->begin()[i] = i; // Won't compile.
          }
      // ...
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-18
        • 1970-01-01
        • 2016-08-17
        • 1970-01-01
        • 1970-01-01
        • 2011-03-04
        • 1970-01-01
        相关资源
        最近更新 更多