Memory Read Error while accessing pointers in object - c++

I have subdivided my question into different sections for better understanding. They are as below:
A) Classes My Question is related to
I have a class TLst representing list as below:
template <class TVal>
class TLst{
public:
typedef TLstNd<TVal>* PLstNd;
private:
int Nds;
PLstNd FirstNd;
PLstNd LastNd;
public:
TLst(): Nds(0), FirstNd(NULL), LastNd(NULL){}
TLst(const TLst&);
~TLst(){Clr();}
explicit TLst(TSIn& SIn);
void Save(TSOut& SOut) const;
**TLst <TVal>& operator = (const TLst <TVal> &t)
{
TLst<TVal>::PLstNd Nd;
if (Len()!=t.Len()) { Clr(); }
for (TLst<TVal>::PLstNd np = t.First(); np!=NULL ; np=np->Next()) {
Nd = AddBack(np->GetVal());
}
return *this;
}**
void Clr(){
PLstNd Nd=FirstNd;
while (Nd!=NULL){PLstNd NextNd=Nd->NextNd; delete Nd; Nd=NextNd;}
Nds=0; FirstNd=NULL; LastNd=NULL;}
bool Empty() const {return Nds==0;}
int Len() const {return Nds;}
PLstNd First() const {return FirstNd;}
PLstNd Last() const {return LastNd;}
**PLstNd AddBack(const TVal& Val){
PLstNd Nd=new TLstNd<TVal>(LastNd, NULL, Val);
if (LastNd!=NULL){LastNd->NextNd=Nd; LastNd=Nd;}
else {FirstNd=Nd; LastNd=Nd;}
Nds++; return Nd;
}**
PLstNd AddFrontSorted(const TVal& Val, const bool& Asc=true);
PLstNd AddBackSorted(const TVal& Val, const bool& Asc=true);
void PutFront(const PLstNd& Nd);
void PutBack(const PLstNd& Nd);
PLstNd Ins(const PLstNd& Nd, const TVal& Val);
void Del(const TVal& Val);
void Del(const PLstNd& Nd);
PLstNd SearchForw(const TVal& Val);
PLstNd SearchBack(const TVal& Val);
friend class TLstNd<TVal>;
};
Similarly I have the class TLstNd to represent a list-node as below:
template <class TVal>
class TLstNd{
public:
TLstNd* PrevNd;
TLstNd* NextNd;
TVal Val;
public:
TLstNd(): PrevNd(NULL), NextNd(NULL), Val(){}
TLstNd(const TLstNd&);
**TLstNd(TLstNd* _PrevNd, TLstNd* _NextNd, const TVal& _Val):
PrevNd(_PrevNd), NextNd(_NextNd), Val(_Val){}**
TLstNd& operator=(const TLstNd&);
TLstNd* Prev() const {Assert(this!=NULL); return PrevNd;}
TLstNd* Next() const {Assert(this!=NULL); return NextNd;}
TVal& GetVal(){Assert(this!=NULL); return Val;}
};
And I have the members and constructors of class TVec (not the entire class) as shown below
template <class TVal>
class TVec{
public:
typedef TVal* TIter;
protected:
int MxVals; // if MxVals==-1, then ValT is not owned by us, we don't free it!
int Vals;
TVal* ValT;
void Resize(const int& _MxVals=-1);
TStr GetXOutOfBoundsErrMsg(const int& ValN) const;
public:
TVec(): MxVals(0), Vals(0), ValT(NULL){}
TVec(const TVec& Vec);
**explicit TVec(const int& _Vals){
IAssert(0<=_Vals); MxVals=Vals=_Vals;
if (_Vals==0){ValT=NULL;} else {ValT=new TVal[_Vals];}}**
TVec(const int& _MxVals, const int& _Vals){
IAssert((0<=_Vals)&&(_Vals<=_MxVals)); MxVals=_MxVals; Vals=_Vals;
if (_MxVals==0){ValT=NULL;} else {ValT=new TVal[_MxVals];}}
explicit TVec(TVal *_ValT, const int& _Vals):
MxVals(-1), Vals(_Vals), ValT(_ValT){}
...
};
And I have the class TPair as below:
class TPair{
public:
TVal1 Val1;
TVal2 Val2;
public:
TPair(): Val1(), Val2(){}
TPair(const TPair& Pair): Val1(Pair.Val1), Val2(Pair.Val2){}
**TPair(const TVal1& _Val1, const TVal2& _Val2): Val1(_Val1), Val2(_Val2){}**
...
TPair& operator=(const TPair& Pair){
if (this!=&Pair){Val1=Pair.Val1; Val2=Pair.Val2;} return *this;}
bool operator==(const TPair& Pair) const {
return (Val1==Pair.Val1)&&(Val2==Pair.Val2);}
...
};
B) What I am doing?
a) I have a TVec>> class "typedef"-ed as
typedef TVec<TPair<TInt, TLst<TInt>>> TNdClass;
b) Next, I create an object of TNdClass, as
TNdClass UsrClassList(MXCLASS_SIZE); //calls TVec(const int& _Vals)
If you see the TVec constructor which is bold, the above call sets Vals, MxVals and allocates MxVals memory for ValT which means UsrClassList allocates memory of size MXCLASS_SIZE*sizeof(TPair>).
c) Next, I am assigning Val1 (of type TInt) and Val2 (of type TLst) to two variables NdCnt (of type TInt) and Nodes (of type TLst). And declare a variable NdClss of type TPair> as below:
TInt NdCnt(0);
TLst<TInt> Nodes;
NdCnt = UsrClassList[VecIdx].Val1; //assigning TInt to TInt
Nodes = UsrClassList[VecIdx].Val2; //assigning TLst<TInt> to TLst<TInt>
TPair<TInt, TLst<TInt> > NdClss; //declaration
d) Next I am adding a TInt of value 1 to Nodes using the AddBack function of TLst (see above in bold) and assign a TPair object instantiated with NdCnt and Nodes to NdClassas below:
Nodes->AddBack(1); //adding a TInt of value 1 to Nodes
e) Finally I am creating a new object of type TPair with NdCnt and Nodes values as parameter and is assigning to NdClss variable (type TPair) declared in step c).
NdClss = TPair<TInt, TLst<TInt>>(NdCnt, Nodes);
This step ends up with an exception with memory read error.
Further down the code, when I am debugging the values of Nodes.First()->NextNd or Nodes.First()->PrevNd the compiler gives "memory read error" which I feel indicates that the NextNd and PrevNd pointers are not allocated with memory.
When I debug the code, I get the value '???' for the watch variables PrevNd and NextNd:
- FirstNd 0x00e6b830 {PrevNd=0x00000000 NextNd=0x00000000 Val={...} } TLstNd<TInt> *
+ PrevNd 0x00000000 {PrevNd=??? NextNd=??? Val={...} } TLstNd<TInt> *
+ NextNd 0x00000000 {PrevNd=??? NextNd=??? Val={...} } TLstNd<TInt> *
+ Val {Val=0 Mn=-2147483648 Mx=2147483647 ...} TInt
- LastNd 0x00e6b830 {PrevNd=0x00000000 NextNd=0x00000000 Val={...} } TLstNd<TInt> *
+ PrevNd 0x00000000 {PrevNd=??? NextNd=??? Val={...} } TLstNd<TInt> *
+ NextNd 0x00000000 {PrevNd=??? NextNd=??? Val={...} } TLstNd<TInt> *
+ Val {Val=0 Mn=-2147483648 Mx=2147483647 ...} TInt
Any suggestions of why the memory for Nodes.First()->NextNd and Nodes.First()->PrevNd are not allocated? And what I need to do to allocate the memory of those two pointers in TLst class?
Look forward to replies.
Somnath

I will try to answer. But my eyes are bleeding right now after reading your question...
For your first question :
I do not see in your code the allocation of TLstNd::PrevNd and TLstNd::NextNd.
And you are saying that you are having a memory read error after accessing to these members...
May be you should allocate them...
For your second question :
Use the keyword new to allocate objects...

Related

How to design a class with const, non const member function and it can take over const raw pointer?

I have a class, it can define some operations on a raw pointer.
For example, the class is called Vector.
class Vector
{
public:
explicit Vector(double *ptr_, int size_)
:ptr(ptr_), size(size_)
{
}
// some operation change data in ptr
void notConstOperation()
{
ptr[0]=ptr[0]+1;
}
// some operation do not change data in ptr
double constOperation() const
{
return ptr[0];
}
private:
double *ptr;
int size;
};
And I have a lot of others operations on Vector
int doNotConstOperation(Vector &vec);
int doConstOperation(const Vector &vec);
My problem is, I find I can not create the Vector object from a raw const pointer.
Vector createVectorFromNonConstPtr(const *ptr, int size)
{
// ok.
return Vector(ptr, size);
}
Vector createVectorFromConstPtr(const double *ptr, int size)
{
// can not create, because the args in Vector is not const.
return Vector(ptr, size);
}
I want to use the Vector in the follow way:
// using const ptr
const double *cptr;
const Vector cvec = createVectorFromConstPtr(cptr, 10);
cvec.constOperation();
doConstOperation(cvec);
// using non-const ptr
const double *ptr;
Vector vec = createVectorFromPtr(cptr, 10);
vec.notConstOperation();
doNotConstOperation(vec);
I know splitting the class into Vector and ConstVector can help.
But it leads to some verbose, the const operation will be written twice.
How can I implement that?
Any suggestion is I looking forward. Thanks for your time.
Any suggestion is I looking forward
Inheritance.
class ConstVector {
const double *ptr;
protected:
double *_ptr() {
return const_cast<double *>(ptr);
}
void _set_ptr(double *new_ptr) {
ptr = new_ptr;
}
friend Vector;
};
class Vector : ConstVector {
// some operation change data in ptr
using ConstVector::ConstVector;
void notConstOperation() {
// _ptr() is inherited.
_ptr()[0] = _ptr()[0]+1;
}
}
Template overload.
template<bool isconst>
class Vector {
double *ptr;
Vector(double *ptr) : ptr(ptr) {}
template<int empty = 1>
Vector(const double *ptr,
typename std::enable_if<isconst && empty>::type* = 0
) : ptr(const_cast<double *>(ptr)) {}
typename std::enable_if<!isconst>::type notConstOperation() {
ptr[0] = ptr[0] + 1;
}
};
Runtime tracking.
class Vector {
bool isconst;
double *ptr;
Vector(double *ptr) : ptr(ptr), isconst(0) {}
Vector(const double *ptr) : ptr(const_cast<double *>(ptr)), isconst(1) {}
void notConstOperation() {
assert(!isconst);
....
}
};
Or return a const vector and const cast to construct it:
class Vector
{
public:
Vector(double *ptr, int size)
: ptr(ptr), size(size) {}
void notConstOperation() { .... }
double constOperation() const { ... }
private:
double *ptr;
int size;
};
Vector createVectorFromNonConstPtr(double *ptr, int size)
{
return Vector(ptr, size);
}
const Vector createVectorFromConstPtr(const double *ptr, int size)
{
return Vector(const_cast<double*>(ptr), size);
}
a const double* pointer is a pointer which preserve the value of the variable it is pointing to. The class Vector has (among its purposes) ways to change the value pointed to by this pointer. In short, the const qualifier is a kind of programmer's rule. The rule is : You can't change the value of the variable.
The compiler detect your attempt to manipulate the variable with objects that might change its value and consider it an error.
The problems start as soon as the compiler assigns to your member ptr (which is not aconst double *but adouble *) the value of your variable const double * ptr. This assignment can't happen since you can't assign to a double* the value of a const double*.
You can basically try to compile the following example.
int main() {
const double* ptr = nullptr;
double* error = ptr;
}
a const_cast<double*> could solve this issue.
int main() {
const double* ptr = nullptr;
double* ok = const_cast<double*>(ptr);
}
I personally don't like const_cast with removing const qualifier to the type, i think i would prefer to make two classes : class VectorView and class Vector which inherit the first.

C++ comparator function does not take 2 arguments

I'm trying to implement a generic heap in C++. In order to make it generic as possible I'm trying to allow the heap to take a comparator to allow different kinds of heap ordering. However I've never used comparators before and I'm running into an issue. Here is the the setup for my heap.
template <typename T>
class greater {
public:
bool operator()(const T& a, const T& b) const { return a > b; }
};
template <typename T, typename C = greater<T> >
class heap {
public:
//constructors
heap();
heap(const heap& other);
heap& operator= (const heap& other);
//destructor
~heap();
//operations
void push(const T& datum);
T& peek() const;
void pop();
//status
bool empty() const { return tree.empty(); }
int size() const { return tree.size(); }
//debug
void print() const;
private:
std::vector<T> tree;
//auxilliary functions
int parent(int index) { return (index - 1) / 2; }
int left(int index) { return 2 * index; }
int right(int index) { return 2 * index + 1; }
void swap(int a, int b) {
T temp = tree[a];
tree[a] = tree[b];
tree[b] = temp;
}
void bubble_up(int index);
void bubble_down(int index);
};
But for my implementation of the bubble_up method I get the following Visual Studio Error: 'compare':function does not take 2 arguments | Error Code:C2660
The error references the line of the while loop in the implementation which is shown below.
template <typename T, typename C>
void heap<T, C>::bubble_up(int index) {
C compare;
int parent_index = parent(index);
while (compare(tree[parent_index], tree[index]) && parent_index >= 0) {
swap(parent_index, index);
index = parent_index;
parent_index = parent(index);
}
}
I'm sure that I've handled using the comparison function poorly, but I'm struggling to find a clear explanation for why this is wrong from my googling so any advice would be appreciated.

Are there any alternatives to making const version of class?

In C++ I'm often facing a situation when I need to prepare const and non-const version of class in analogy to const_iterator and iterator from standard library.
class const_MyClass
{
public:
const_MyClass(const int * arr):
m_arr(arr)
{
}
int method() const; //does something with m_arr without modifying it
private:
const int * m_arr;
}
class MyClass
{
public:
MyClass(int * arr):
m_arr(arr)
{
}
int method() const; //does something with m_arr without modifying it
void modify(int i); //modify m_arr
private:
int * m_arr;
}
The problem with this is that I need to repeat whole code of const_MyClass in MyClass and distribute any changes in API to both classes. Thus sometimes I inherit const_MyClass and do some const_casts, which also isn't perfect and pretty solution. Still when I want to pass const_MyClass instance by reference it looks moronic:
void func(const const_MyClass & param)
Instance param is marked with two "consts", and it has only const methods...
This is where const constructors would be handy, but are there any existing alternatives?
Some use examples to explain problem better:
//ok to modify data
void f(int * data)
{
MyClass my(data);
my.modify();
...
}
//cant modify data, cant use MyClass
void fc(const int * data)
{
const_MyClass my(data);
int i = my.method();
...
}
You can make a template class to act as a base, like this:
template<typename T>
class basic_MyClass
{
public:
basic_MyClass(T * arr) :m_arr(arr) {}
int method() const; //does something with m_arr without modifying it
private:
T * m_arr;
};
Then, for your const version, since it doesn't add anything, you can just use a typedef:
typedef basic_MyClass<const int> const_MyClass;
For your non-const version, you can inherit:
class MyClass : public basic_MyClass<int>
{
public:
using basic_MyClass::basic_MyClass; // inherit all the constructors
void modify(int i); //modify m_arr
};
Have you considered simply tracking two pointers and raising exceptions from the mutable operations when no mutable value is available? Maybe an example will help describe what I am thinking of.
class MyClass
{
public:
MyClass(int *mutable_data):
m_mutable_view(mutable_data), m_readonly_view(mutable_data)
{
}
MyClass(const int *immutable_data):
m_mutable_view(NULL), m_readonly_view(immutable_data)
{
}
int retrieve_value(int index) {
return m_readonly_view[index];
}
void set_value(int index, int value) {
require_mutable();
m_mutable_view[index] = value;
}
protected:
void require_mutable() {
throw std::runtime_error("immutable view not available");
}
private:
const int *m_readonly_view;
int *m_mutable_view;
};
The idea is pretty simple here - use a sentinel value to indicate whether modifications are possible or not instead of depending on the type system to do that for you. Personally, I would think about doing the inheritance based approach that #BenjaminLindley suggested but I wanted to present a slightly different solution that might not have occurred to you.
After talk with Neil Kirk I realized what I was doing wrong. I started by separating data from logic as he suggested.
This attempt resulted in two classes MyClassPtr and const_MyClassPtr. They only provide functions for data access (like iterators) and may look like that:
class const_MyClassPtr
{
public:
const_MyClassPtr(const int * arr);
int operator [](int i) const;
const int * ptr() const;
private:
const int * m_arr;
}
class MyClassPtr
{
public:
MyClassPtr(int * arr);
int operator [](int i) const;
int & operator [](int i);
const int * ptr() const;
int * ptr();
//promotion to const pointer
const_MyClassPtr () const {return const_MyClassPtr(m_arr);}
private:
int * m_arr;
}
Now it is clear that objects of these classes should be treated like pointers, so when I use them as function parameters I pass them by value!
void func(const_MyClassPtr param) //instead of void func(const const_MyClass & param)
To provide methods I have created MyClassOp class template and used static polymorphism.
template <class DERIVED>
class MyClassOp
{
public:
const DERIVED & derived() const {return static_cast<const DERIVED &>(*this)}
DERIVED & derived() {return static_cast<DERIVED &>(*this)}
int method() const; //operates on derived() const
void modify(int i); //operates on derived()
}
MyClassOp is a collection of methods. It does not have state. In general it is a trait. To make these methods accessible I overloaded -> and * operators
class const_MyClassPtr : private MyClassOp<const_MyClassPtr>
{
public:
const MyClassOp<MyClassPtr> * operator ->() const {return this;}
const MyClassOp<MyClassPtr> & operator *() const {return *this;}
...
}
class MyClassPtr : private MyClassOp<MyClassPtr>
{
public:
MyClassOp<MyClassPtr> * operator ->() {return this;}
MyClassOp<MyClassPtr> & operator *() {return *this;}
...
}
This works O.K., but is a bit cumbersome. If I have for example equality operator I need to write something like *myptr1 == myptr2 to compare values kept by two MyClassPtr objects (it's easy to make a mistake and compare myptr1 == myptr2 or expect that something like *myptr1 == *myptr2 could work). Also when I have allocating type:
class MyClass : public MyClassOp<MyClass>
{
MyClass(int x, int y, int z);
...
int m_arr[3];
}
I would want to be able to use temporaries as function arguments.
void f(const_MyClassPtr my);
//use temporary when calling f()
f(MyClass(1, 2, 3));
I can do this by providing conversion operators or conversion constructors (that convert MyClass to const_MyClassPtr). But then const_MyClassPtr behaves more like reference than pointer. If iterators are generalization of pointers then why one could not imitate reference? Therefore I divided MyClassOp into two parts (const and non const) and replaced -> and * operators implemented by const_MyClassPtr and MyClassPtr with public inheritance and changed their names to ressemble reference. I ended up with following structures.
MyClassOp : public const_MyClassOp
const_MyClassRef : public const_MyClassOp<const_MyClassRef>
MyClassRef : public MyClassOp<MyClassRef>
MyClass : public MyClassOp<MyClass>
However const_MyClassRef and MyClassRef are not perfect generalization of reference as it impossible to imitate some of C++ reference properties, so Ref suffix is there to denote reference-like structure.
Maybe you can find some hints in effective c++ item 4 "Avoid duplication in const and non-const Member function"
I may summarize like following ( it makes you avoid code duplication even if using somewhat ugly cast ):
struct my_class
{
my_class(int x):_x(x){};
const int& method(void) const;
int& method(void);
int _x;
};
const int& my_class::method(void) const //func for const instance
{
return _x;
}
int& my_class::method(void) //func for normal instance
{
return const_cast<int& >(static_cast<const my_class& >(*this).method()) ;
}
int main()
{
my_class a(1);
const my_class b(2);
a.method() = 5;
cout << a.method() << endl;
//b.method() = 4; //b is const, wont compile
cout << b.method() << endl;
return 0;
}

Generic Type Container implemented with Templates

I have a class that can generically hold any (primitive) type:
class Value
{
private:
int i_value;
unsigned int ui_value;
long l_value;
unsigned long ul_value;
short s_value;
float f_value;
double d_value;
char c_value;
bool b_value;
std::string str_value;
int type;
void setValue(int value);
void setValue(unsigned int value);
void setValue(long value);
void setValue(unsigned long value);
void setValue(short value);
void setValue(float value);
void setValue(double value);
void setValue(char value);
void setValue(bool value);
void setValue(std::string value);
public:
Value(int value);
Value(unsigned int value);
Value(long value);
Value(unsigned long value);
Value(short value);
Value(float value);
Value(double value);
Value(char value);
Value(bool value);
Value(std::string value);
Value(Value& other); //Copy Constructor
~Value();
int getType();
std::string toString(int format);
};
This is nice, because I can do something like:
Value * v1 = new Value(55);
Value * v2 = new Value(1.2);
Value * v3 = new Value("yes");
Value * v4 = new Value(true);
However, as you can see, it's pretty ugly; tons of overloading of everything to make it work. I was thinking templates could make this generic. However, as far as I can tell, you always have to specify the type, which sort of defeats the whole purpose of the class.
For example:
Value<int> * v1 = new Value<int>(55);
Value<double> * v2 = new Value<double>(1.2);
Value<string> * v3 = new Value<string>("yes");
Value<bool> * v4 = new Value<bool>(true);
If I use templates, I can no longer do something like vector<Value *> like I could before. Is this correct, or am I missing some aspect of templates that could help in this situation?
All you need is a parent base class for the template one:
class BaseValue
{
public:
virtual ~BaseValue()
{}
};
template<typename T>
class Value : public BaseValue
{
public:
Value(const T& value)
:m_value(value)
{}
void set(const T& value)
{
m_value = value;
}
const T& get()
{
return m_value;
}
virtual ~Value()
{}
private:
T m_value;
};
std::vector<BaseValue*> values;
values.push_back(new Value<int>(1)); // int
values.push_back(new Value<double>(1.0)); // double
values.push_back(new Value<char*>("asdf")); // pointer to array on stack :(
values.push_back(new Value<char>('c')); // char
First question: Use a template factory function instead of new.
Second question: Use a common base-class.
In order to be able to properly delete the objects pointed to by the pointers on the vector, you need a virtual destructor. Also, in order to do anything useful with the pointers to the base class, you need virtual methods in the base class.
Example:
class ValueBase
{
public:
virtual ~ValueBase() = default;
virtual void Print(std::ostream & os) const = 0;
};
std::ostream & operator<< (std::ostream & os, const ValueBase & value)
{
value.Print(os);
return os;
}
template<typename T> class Value : public ValueBase
{
T value;
public:
Value(const T & v) : value(v) {}
const T & Get() const;
void Set(const T & v);
void Print(std::ostream & os) const
{
os << value;
}
// ...
};
template<typename T> Value<T> * NewValue(const T & v)
{
return new Value<T>(v);
}
Now you can do
ValueBase * v1 = NewValue(55);
ValueBase * v2 = NewValue(1.2);
ValueBase * v3 = NewValue<std::string>("yes");
ValueBase * v4 = NewValue(true);
std::vector<ValueBase *> vec;
vec.push_back(v1);
vec.push_back(v2);
vec.push_back(v3);
vec.push_back(v4);
vec.push_back(NewValue(2350983444325345ll));
for (const auto & entry : vec)
{
std::cout << *entry << " ";
}
std::cout << "\n";
Note that you normally do not need the template argument of NewValue, since it will be deduced. With "yes" this does not work, since Value<T> will be instantiated with T = char [4] which would require you to use strcpy in the constructor. I find it quite nice to explicity state that a conversion is needed as above. If you prefer this implicitly, do an overload:
Value<std::string> * NewValue(const char * v)
{
return new Value<std::string>(v);
}
Make sure to delete the contents manually
for (const auto & entry : vec)
{
delete entry;
}
vec.clear();
or use std::unique_ptr instead of the bare pointer:
template<typename T> std::unique_ptr<Value<T>> UniqueValue(const T & v)
{
return std::unique_ptr<Value<T>>(new Value<T>(v));
}
std::vector<std::unique_ptr<ValueBase>> vec;
vec.push_back(NewValue(4.5));
If you extend Value and it turns out you need to do something in the destructor, you have to implement the copy constructor, assignment operator and possibly also the move constructor and move assignment operator. ("Rule of Three" or "Rule of Five".) In the above version the "Rule of Zero" still applies, since the destructor is still the same as the implicitly defined one (= default).
If you add the destructor it should be virtual. Otherwise you might get memory leaks if you delete the VirtualBase pointers.
Of course you can do templates, but you also need to do polymorphic.
class StupidAndEmpty {} // add virtual destructor if Value needs a destructor
template<class dType>
Value : StupidAndEmpty {
// do smart things with dType
}
vector<StupidAndEmpty *> notSoStupid;
Only problem is how do you use them when you get them back from vector.

Unified wrapper around const and non-const pointers

I am using GNU Scientific Library in my C++ project. For convience, I would like to trasparently wrap gsl_vector* in a C++ class (to add a bunch of domain specific functions and to simplify interface). But I am getting perplexed with how to deal with const gsl_vector*. Let me explain. Let me start with this minimalistic wrapper.
class Vector {
gsl_vector* vector_;
public:
Vector(gsl_vector* vector): vector_(vector) {}
double& operator()(int i) {
return *gsl_vector_ptr(vector_, i);
}
};
Suppose, further, that I have two functions. One is defined as follows:
int f(Vector& x) {
\\ do some math, e.g. x(0) = 0.0;
return 0;
}
Another one is a callback function that has to use GSL types, and is defined as follows:
int gsl_f(gsl_vector* x) {
Vector xx(x);
return f(xx);
}
This works fine. Now, suppose the callback has a constant signature:
int gsl_f(const gsl_vector* x);
Then I can redefine my Vector class and my f function accordingly:
class Vector {
const gsl_vector* vector_;
public:
Vector(const gsl_vector* vector): vector_(vector) {}
const double& operator()(int i) const {
return *gsl_vector_const_ptr(vector_, i);
}
};
int f(const Vector& x) {
\\ do some math
return 0;
}
Also works. Now, I want my wrapper class to suit both situations. For example, I want to be able to do the following, preserving the safety of const:
int f(const Vector& x, Vector& y) {
\\ do some math
return 0;
}
int gsl_f(const gsl_vector* x, gsl_vector* y) {
Vector yy(y);
return f(x, yy);
}
I can do it by having a Vector with two pointers, const and non-const, and remembering whether it was initialized from a const or non-const member. My question is, can I do it without runtime checks? After all, all the information is there at the compile time.
Proposal (not wonderful, but should work):
class Vector {
gsl_vector* vector_;
const gsl_vector* const_vector_;
public:
Vector(const gsl_vector* vector): vector_(nullptr), const_vector_(vector) {}
Vector(gsl_vector* vector): vector_(vector), const_vector_(vector) {}
const double& operator()(int i) const {
return *gsl_vector_ptr(const_vector_, i);
}
double& operator () (int i) {
return *gsl_vector_ptr(vector_, i);
}
};
Second possibility:
class Vector {
private:
gsl_vector* vector_;
Vector(gsl_vector* vector): vector_(vector) {}
public:
static const Vector* Create (const gsl_vector* vector) {
return new Vector (const_cast<Vector *> vector);
}
static Vector* Create (gsl_vector* vector) {
return new Vector (vector);
}
const double& operator()(int i) const {
return *gsl_vector_ptr(vector_, i);
}
double& operator () (int i) {
return *gsl_vector_ptr(vector_, i);
}
};
Combining both classes should work as expected, have you tried it?
class Vector {
gsl_vector* vector_;
public:
Vector(gsl_vector* vector): vector_(vector) {}
const double& operator()(int i) const {
return *gsl_vector_ptr(vector_, i);
}
double& operator()(int i) {
return *gsl_vector_ptr(vector_, i);
}
operator const_Vector()
{
return const_Vector(vector_);
}
};
class const_Vector {
const gsl_vector* vector_;
public:
const_Vector(const gsl_vector* vector): vector_(vector) {}
const double& operator()(int i) const {
return *gsl_vector_ptr(vector_, i);
}
};
Function signature needs to look this way:
int f(const_Vector& x, Vector& y) {
\\ do some math
return 0;
}
This followes a similar scheme like the iterator and const_iterator.
Maybe you have a situation which this will not work,. you should post this situation and we can try to solve it.
You can also use some kind of inheritance with pointer to data. further - templates can be used to create overloaded function returning either one or second version depending on input pointer types.
class JSONChannelFullConfigConst:
public JSONObjectRenderer {
public:
JSONChannelFullConfigConst(const uint8_t * channel_id,
const sensors_single_channel_config_t * cfg) :
j_channel_id(channel_id),
j_cfg(cfg) {
}
private:
const uint8_t * const j_channel_id;
const sensors_single_channel_config_t * const j_cfg;
void renderFields(rlf::UcOstreamBase& os) const;
public:
uint8_t getId() const {
return *j_channel_id;
}
};
class JSONChannelFullConfig:
public JSONChannelFullConfigConst,
public JSONObjectParser {
public:
JSONChannelFullConfig(uint8_t * channel_id, sensors_single_channel_config_t * cfg) :
JSONChannelFullConfigConst(channel_id, cfg),
j_channel_id(channel_id),
j_cfg(cfg) {
}
void setId(uint8_t id) {
*j_channel_id = id;
}
private:
uint8_t * const j_channel_id;
sensors_single_channel_config_t * const j_cfg;
virtual bool parseNameValuePair(const char * name, rlf::UcIstream & value);
};