I have a relationship between two classes and some additional functional code illustrated in the below example. The MiddleMan
class holds a couple of containers of pointers to DataObject
class instances. I want to enforce read-only access to the data objects in one container, while allowing write access to the data containers in the other. Users of MiddleMan
should never be able to modify the containers themselves directly (the ptr_vector
members).
I guess there is const promotion happening to the DataObject
pointers when accessed through the MiddleMan
const member function. How can I avoid this? In my object relationship, MiddleMan
does not logically own the DataObject
instances. Thus, I do not want the DataObject
instances const-protected.
I have used the boost::ptr_vector
container as I understand the STL containers can be more problematic for this sort of thing. Didn't solve my problem though.
I am happy to use const_cast in MiddleMan
, but I don't see how to.
// 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;
}
I'm getting the compiler output:
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
One working scenario uses const_cast
in accessing the outputVars. I'm not able to return a reference to the whole container, but I can get the functionality I need returning begin and end iterators.
// 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;
}