当容器在 C++ 中为 const 时,如何对容器持有的对象进行非 const 访问

Posted

技术标签:

【中文标题】当容器在 C++ 中为 const 时,如何对容器持有的对象进行非 const 访问【英文标题】:How to have non-const access to object held by a container when the container is const in C++ 【发布时间】:2013-01-10 01:47:07 【问题描述】:

我有两个类之间的关系以及下面示例中说明的一些附加功能代码。 MiddleMan 类包含几个指向 DataObject 类实例的指针容器。我想强制对一个容器中的数据对象进行只读访问,同时允许对另一个容器中的数据容器进行写访问。 MiddleMan 的用户永远不能直接修改容器本身(ptr_vector 成员)。

我猜想当通过MiddleMan const 成员函数访问时,DataObject 指针会发生 const 提升。我怎样才能避免这种情况?在我的对象关系中,MiddleMan 在逻辑上并不拥有DataObject 实例。因此,我不希望 DataObject 实例受到 const 保护。

我使用了boost::ptr_vector 容器,因为我知道 STL 容器对于这类事情可能会更成问题。虽然没有解决我的问题。 我很高兴在 MiddleMan 中使用 const_cast,但我不知道如何使用。

// const correctness access through middleman example
// g++ -I/Developer/boost  ptr_container_ex.cc
#include <boost/ptr_container/ptr_vector.hpp>

struct DataObject

    DataObject(size_t n) : _data(new float[n]) 
    ~DataObject() delete _data;
    float * dataNonConst()  return _data; 
    const float * dataConst() const  return _data; 
    float * _data;
;


struct MiddleMan


    typedef boost::ptr_vector<DataObject> containerVec_t;

    const containerVec_t & inputVars() const  return _inputVars; 
    const containerVec_t & outputVars() const  return _outputVars; 

    void addInputVar(  DataObject * in  )  _inputVars.push_back( in ); 
    void addOutputVar( DataObject * out )  _outputVars.push_back( out ); 

    containerVec_t _inputVars, _outputVars;

;

// just an example that the DataObject instances are managed externally
DataObject g_dataInstances[] = DataObject(1), DataObject(2), DataObject(3);

MiddleMan theMiddleMan;


int main()

    theMiddleMan.addInputVar( &g_dataInstances[0]);  // this is just setup
    theMiddleMan.addOutputVar( &g_dataInstances[1]);

    const MiddleMan & mmRef = theMiddleMan; // I actually only have a const ref to work with

    // read data example
    const MiddleMan::containerVec_t & inputs = mmRef.inputVars();
    float read = inputs[0].dataConst()[0];

    // write data example
    const MiddleMan::containerVec_t & outputs = mmRef.outputVars();
    float * data_ptr = outputs[0].dataNonConst(); // COMPILER ERROR HERE:

    return 0;

我正在获取编译器输出:

ptr_container_ex.cc: In function ‘int main()’:
ptr_container_ex.cc:49: error: passing ‘const DataContainer’ as ‘this’ argument of ‘float* DataContainer::dataNonConst()’ discards qualifiers

【问题讨论】:

【参考方案1】:

您需要在每个不具有 const 访问权限的地方排除 const 修饰符:

containerVec_t & outputVars()  return _outputVars;  //Change definition in MiddleMan class

MiddleMan::containerVec_t & outputs = theMiddleMan.outputVars(); //Change reference type
float * data_ptr = outputs[0].dataNonConst(); //No compiler error here

【讨论】:

通过这种方法,MiddleMan 的用户可以修改 outputVars 容器。 outputs.push_back(&amp;g_dataInstances[0]);这与界面的意图相反。【参考方案2】:

一个工作场景使用const_cast 访问输出变量。我无法返回对整个容器的引用,但我可以获得返回开始和结束迭代器所需的功能。

// const correctness access through middleman example
// g++ -I/Developer/boost  ptr_container_ex.cc
#include <boost/ptr_container/ptr_vector.hpp>

struct DataObject

    DataObject(size_t n) : _data(new float[n]) 
    ~DataObject() delete _data;
    float * dataNonConst()  return _data; 
    const float * dataConst() const  return _data; 
    float * _data;
;


struct MiddleMan

    typedef boost::ptr_vector<DataObject> containerVec_t;

    containerVec_t::iterator outputVarsBegin() const  return const_cast<containerVec_t&>(_outputVars).begin(); 
    containerVec_t::iterator outputVarsEnd() const  return const_cast<containerVec_t&>(_outputVars).end(); 

    const containerVec_t & inputVars() const  return _inputVars; 

    void addInputVar(  DataObject * in  )  _inputVars.push_back( in ); 
    void addOutputVar( DataObject * out )  _outputVars.push_back( out ); 

    containerVec_t _inputVars, _outputVars;

;

// just an example that the DataObject instances are managed externally
DataObject g_dataInstances[] = DataObject(1), DataObject(2), DataObject(3);

MiddleMan theMiddleMan;


int main()

    theMiddleMan.addInputVar( &g_dataInstances[0]);  // this is just setup
    theMiddleMan.addOutputVar( &g_dataInstances[1]);

    const MiddleMan & mmRef = theMiddleMan; // I actually only have a const ref to work with

    // read data example
    const MiddleMan::containerVec_t & inputs = mmRef.inputVars();
    float read = inputs[0].dataConst()[0];

    // write data example
    float * data_ptr2 = mmRef.outputVarsBegin()->dataNonConst(); // WORKS

    return 0;

【讨论】:

以上是关于当容器在 C++ 中为 const 时,如何对容器持有的对象进行非 const 访问的主要内容,如果未能解决你的问题,请参考以下文章

《深入实践C++模板编程》之六——标准库中的容器

如何在 Flutter 中为容器的底部边框设置动画?

C++ STL中的 iterator 和 const_iterator

如何在 C++ 模板容器中实现 erase() 方法

C++第10课 STL容器 (三1)

对容器中项目的 const-correct 指针访问