I am trying to get multiple pointer in one get methods, without leaving the user the right to modify the data. Here is my implementation :
class A {
public:
bool getAB( int** a, int** b ) const
protected :
int * a_;
int * b_;
}
bool getAB( int** a, int** b ) const
{
*a = a_;
*b = b_;
return true;
}
But this way, user can modify, and even free the data.
I could implement like two different getter wich return const int*, but i would like to know if there is a correct way to do that.
In c++, the proper way to return multiple values is by reference:
class A {
public:
bool getAB( int*& a, int*& b ) const
{
a = _a;
b = _b;
}
protected :
int * a_;
int * b_;
}
(I also made the method inline to simplify the example)
If you want to disallow altering the data, return a pointer to const:
class A {
public:
bool getAB( const int*& a, const int*& b ) const
{
a = _a;
b = _b;
}
protected :
int * a_;
int * b_;
}
Note that the user can still call delete (but not free) on the result of getAB; see this question for more info. If you want to disallow delete, you can replace pointers by smart pointers (e.g. std::unique_ptr).
Actually, if you want your code to be compatible with c++ exceptions, you should never hold two pointers in your class (and rarely, if ever, hold one pointer).
You can indeed protect a little more the internal values, but it will be hard to forbid a delete. Here is the best I could do
class A {
public:
bool getAB( const int ** const a, const int ** const b ) const;
A(int * a, int *b): a_(a), b_(b) {}
protected :
int * a_;
int * b_;
};
bool A::getAB( const int ** const a, const int ** const b ) const
{
*a = a_;
*b = b_;
return true;
}
int main() {
int i=1;
int j=2;
A a(&i, &j);
const int * p1;
const int * p2;
// int * p2; error
a.getAB(&p1, &p2);
// *p1 = 3; error
// delete p1; unfortunately gives no errors
cout << *p1 << " " << *p2 << endl;
return 0;
}
It does require a pointer to const, but delete is unfortunately allowed. And it is not possible to pass a const pointer, because a const pointer has to be immediately initialized.
Related
The code below is a simplified version of the actual problem I am facing.
Assume I do not have permission to modify class A (as it is external library), and its already widely used in my existing code base.
The const & assignment from a temporary object (direct constructor) which also return a const & member variable via implicit conversion is not valid in this case.
How do I prevent or make it legal in this case so that the caller gets the correct A value?
class A
{
public:
A() { }
A(int _r, int _g, int _b)
: r(_r), g(_g), b(_b)
{
}
~A(){ }
int GetR() const { return r; }
int GetG() const { return g; }
int GetB() const { return b; }
private:
int r = 0;
int g = 0;
int b = 0;
};
class Foo
{
public:
Foo() : Foo(A()) {}
Foo(int _r, int _g, int _b) : a(A(_r, _g, _b)) {}
explicit Foo(const A& _a) : a(_a) {}
Foo& operator=(const A& a)
{
*this = Foo(a);
return *this;
}
operator A() const { return a; }
operator const A&() const { return a; }
private:
A a;
};
int main()
{
const A& a = Foo(200, 100, 300);
std::cout << a.GetR() << a.GetG() << a.GetB() << endl; // I may not get 200 100 300 here as Foo is already out of scope
return 0;
}
Motivation
Some background on why I am implementing a class as above. The actual purpose of class Foo is to contain 2 different objects, which actually has the same purpose, just different way of storing data internally. For example, let's say class A and class B, which stores RGB value of color in int and floating (normalized) respectively. And as mentioned above, I do not have permission to modify class A, and its already widely used in my code base.
There are tons of function in my code base which takes in const A& and const B& as a function param. So I am trying to unify this 2 classes for a particular case, where I can just pass in Foo in those places and it will work as expected.
You can apply ref-qualified member functions (since C++11), i.e. mark the conversion operator with lvalue-reference, to prevent it being called on temporaries (rvalues).
class Foo
{
public:
... ...
operator A() const { return a; }
operator const A&() const & { return a; }
operator const A&() && = delete;
... ...
};
Then
const A& a = Foo(200, 100, 300); // invalid; invokes deleted operator
const A& a = static_cast<A>(Foo(200, 100, 300)); // fine; invokes operator A()
Given class A and Class B. I need to use the "add" function as shown in the cpp file to store an object reference of class B in an object array of class A.
I should be able to use "->" as shown in the cpp file to call Class B's "print" function.
Compile Time Error: void* is not a pointer-to-object type
So how do I solve this error?
==================================================================================
// header file
// ABC.h
class A{
private:
size_t size_;
void * a_[256];
static int index_;
public:
void add(void * obj);
void * operator[](int x){
return a_[x];
}
};
class B {
private:
const char * f_;
const char * l_;
public:
B(const char * fn, const char * loc ):f_(fn), l_(loc){ A(); };
void print();
};
// cpp file
#include "ABC.h"
int A::index_ = 0;
inline void A::add(void* obj){
void * insertionPoint = static_cast<char *>(a_[index_]) + ( size_ * index_ );
memcpy( insertionPoint, obj, size_);
++index_;
}
inline void B::print(){
...
}
int main()
{
A a;
B b( "Name", "Some string");
a.add( &b );
a[0]->print(); // <-- This should be an object reference to B, but it is producing the error.
return 0;
}
Output:
Name Some string
The following method makes no sense:
virtual void add(A * obj){
*this = dynamic_cast<void*>(obj);
}
in case you want to store pointers to other instances of A within A, create an array of pointers where you will hold them, trying to "replace" the current instance (i.e. *this =...) makes no sense.
Also note that dynamic_cast would make sense if you want to examine whether A* points to instance of B:
A* a = new B();
// in compile time it's A*, but does it really point to instance of B? :
B* b = dynamic_cast<B*>(a);
Why don't you start with something simpler? Let's say:
class A {
public:
virtual void print() { std::cout << "a"; }
};
class B : public A {
public:
void print() /* const */ { std::cout << "b"; }
};
used as:
A* a = new A();
A* b = new B();
a->print();
b->print();
which (as it stands) outputs ab. Then you can change the B's print() to const and realize that the constness of method actually matters.
The solution involved advice from all above comments
Compare the differences between the question and answer to see the solution, fully.
What I needed to do was change class A's private a_ member to type A: A * _a[256]
NEXT: I needed to change the operator[] and the add method's parameter to type A, as well: A * operator[](A * obj)
NEXT: I needed to add a virtual void print()for inheritance purposes to class A.
FINALLY: Class B needed to inherit class A
Below is working code
NOTE: I am not sure if this code is entirely secure or deals with memory issues properly, but I do know that it prints to output what it was intended to print.
==================================================================================
// header file
// ABC.h
class A{
private:
size_t size_;
A * a_[256];
static int index_;
public:
void add(A * obj);
A * operator[](int x); // Any subclass object reference of A can be assigned now.
virtual void print()const; // Virtual tells the compiler to look for other void print methods first.
};
class B : public A{
private:
const char * f_;
const char * l_;
public:
B(const char * fn, const char * loc ):f_(fn), l_(loc){ A(); };
void print()const;
};
// cpp file
#include "ABC.h"
int A::index_ = 0; // Need to call this here because it is declared static in Class A and can be used dynamically.
inline A * A::operator[](int x){
return a_[x]; // Implements operator[], so class A can act like a container.
}
inline void A::add(A* obj){
a_[index_] = obj; // Adds a base or subclass object reference to class A object array.
++index_; // Need this to remember current index of object reference A's array.
}
inline void A::print()const{}
inline void B::print()const{
std::cout << "B " << firstname_ << " works in " << location_ << std::endl;
}
int main()
{
A a;
B b( "Name", "Some string");
a.add( &b );
a[0]->print();
return 0;
}
Output:
Name Some string
I am having trouble with the initialization of this struct (simplified for example)
struct S{ const float * const * const data;};
Basically I have a buffer of buffers of floats, and I use const to ensure someone using S cannot change anything to this member (read only).
My problem is that this is complicated and hard to read to initialize, I would like to use a lambda that return an const S, and so I could initialize members in my lambda by writing the member name : s.data = ptr;
Now this code is complex and I wonder what could be a better solution.
AFAIK, having struct S{float ** data;} a const S would not protect as efficiently the content of the member, I could not modify S::data, but I could modify *S::data.
How should I do ?
Thank you
Why not just remove the last const?
struct S{ const float * const * data;};
That way you can initialize data however you like, and it still can't be used to modify anything it points to.
data itself can be modified, but should that be prevented, it should simply be private.
The recommended way is to add a constructor to S. This allows you to set the value of data in the ctor initializer list.
struct S
{
explicit S(const float *const *const d) : data(d) {}
const float * const * const data;
};
S GetS()
{
float **data = GetData();
return S(data);
}
If you want to restrict who can change S::data after it has been initialized you can box the member variable and use friendship to allow access. This requires encapsulating the data member in an additional struct that provides conversion and assignment operators.
struct Outer
{
struct S
{
private:
struct ConstBox
{
friend Outer;
ConstBox(const ConstBox& other) : data_(other.data_) {}
explicit ConstBox(const float *const *const data) : data_(data) {}
operator const float* const* () const { return data_; }
private:
ConstBox& operator=(const float * const * data)
{
data_ = data;
return *this;
}
const float * const * data_;
};
public:
S() : data(nullptr) {}
explicit S(const float *const *const d) : data(d) {}
ConstBox data;
};
S DoSomething() const
{
S s(nullptr);
auto f = []() -> S
{
S s;
s.data = new float*[10];
return s;
};
return f();
}
};
typedef Outer::S S;
void FailTest()
{
S s;
s.data = nullptr; // <-- fails
float** v1 = s.data; // <-- fails
const float** v1 = s.data; // <-- fails
// These are ok
const float* const* v2 = s.data;
}
#CaptainObvious's answer is the correct one. Write a constructor for S, taking whatever arguments it needs, and use a member initialiser rather than an assignment statement to set 'data'.
With your simplified example I would simply do:
struct S{ float const * const * const data;};
auto create_buffer() -> float const * const * {
float **buf;
/* ... compute buffer contents */
return buf;
}
S s {create_buffer()};
However, in a comment you mention that you have many members and that initializing members based on order is not sufficiently clear.
struct S { const A a; const B b; const C c; };
S s {x,y,z}; // order based, not readable enough.
const members must be initialized as part of the object's construction. You must either specify them somehow in the initializer, or you must set their value in the class, so that they are set at construction time.
Solution 1
One way to pass them during construction, but in a readable fashion is to use a second object to help initialization:
struct S_initializer { A a; B b; C c; }
struct S {
const A a; const B b; const C c;
S(S_initializer &s) : a(s.a), b(s.b), c(s.c) {}
};
S make_S() {
S_initializer s;
s.a = x;
s.b = y;
s.c = z;
return S{s};
}
The above involves some repitition, which you can avoid by just making the initialization helper object a const member of S:
struct S {
const S_initializer m;
S(S_initializer &s) : m{s} {}
};
S make_S() {
S_initializer s;
s.a = x;
s.b = y;
s.c = z;
return S{s};
}
The tradeoff is that now to access the members of S you have to have an extra .m in there:
A a = s.m.a; // versus just s.a;
Solution 2
A second method relies on a compiler extension; Although not standard C++, gcc and clang implement C99 designated initializers in C++. VC++ does not implement this.
S s { .a = x, .b = y, .c = z };
class c {
private:
int n[10];
public:
c();
~c();
int operator()(int i) { return n[i];};
};
class cc {
private:
public:
c *mass;
cc();
~cc();
c& operator*() const {return *mass;};
};
int somfunc() {
c *c1 = new c();
cc * cc1 = new cc();
(*cc1->mass)(1);
delete c1;
}
I've got a pointer into class cc to class c.
Is there any way to get rid of record like this:
(*cc1->mass)(1);
and write somethink like that:
cc1->mass(1);
is it impossible?
When I saw the tags "c++" and "operator overloading", my mind alarm turns ON.
C++ operator overloading is complex, and some operators like "()" or "->" make it more difficult.
I suggest, before overloading operators, making either a global function or method with the same purpouse, test it works, and later replace it with the operator.
Global friend function example:
class c {
private:
int n[10];
public:
c();
~c();
// int operator()(int i) { return n[i]; }
// there is a friend global function, that when receives a "c" object,
// as a parameter, or declares a "c" object, as a local variable,
// this function, will have access to the "public" members of "c" objects,
// the "thisref" will be removed, when turned into a method
friend int c_subscript(c thisref, int i) ;
};
int c_subscript(c* thisref, int i)
{
return c->n[i];
}
int main()
{
c* objC() = new c();
// do something with "objcC"
int x = c_subscript(objC, 3);
// do something with "x"
return 0;
} // int main(...)
Local function ( "method" ) example:
class c {
private:
int n[10];
public:
c();
~c();
// int operator()(int i) { return n[i]; }
int subscript(int i) ;
};
int c::subscript(int i)
{
return this.n[i];
}
int main()
{
c* objC() = new c();
// do something with "objcC"
int x = c->subscript(objC, 3);
// do something with "x"
return 0;
} // int main(...)
And, finally use the overloaded operator:
class c {
private:
int n[10];
public:
c();
~c();
int subscript(int i) ;
int operator()(int i) { return this.subscript(i); }
};
int c::subscript(int i)
{
return this.n[i];
}
int main()
{
c* objC() = new c();
// do something with "objcC"
int x = c->subscript(3);
// do something with "x"
int x = c(3);
// do something with "x"
return 0;
} // int main(...)
Note that in the final example, I keep the method with a unique identifier.
Cheers.
Could always do this:
class cc {
private:
c *_mass;
public:
c& mass() const {return *_mass;};
};
Now..
cc1->mass()(1);
If mass were an object, not a pointer, you could use the syntax you want:
class cc {
private:
public:
c mass;
cc();
~cc();
const c& operator*() const {return mass;};
};
…
cc1->mass(1);
You can with
(*(*cc1))(1)
because operator() is applied to an object, not a pointer.
You can use
(**cc1)(1);
Or
cc1->mass->operator()(1);
Consider the following code:
class B
{
int x;
public:
B() : x( 10 ) {}
int get_x() const { return x; }
void set_x( int value ) { x = value; }
};
class A
{
boost::shared_ptr<B> b_;
public:
boost::shared_ptr<B> get_b() const { return b_; } // (1)
};
void f( const A& a)
{
boost::shared_ptr<B> b = a.get_b();
int x = b->get_x();
b->set_x( ++x ); // (2)
}
int main()
{
A a;
f( a );
return 0;
}
In this code (2) compiles without any errors or warnings independently the fact that get_b is a const function and a is a const object.
My question is how do you deal with this situation? The best I could use is to change (1) to the following:
boost::shared_ptr<const B> get_b() const { return b_; } // (1)
But I should always remember that I should add const to the return type. That's not very convenient. Is there a better way?
This doesn't actually have anything to do with shared pointers per se. I mean if you had a plain pointer you'd have exactly the same problem and would solve it in exactly the same way, that is
const B* get_b() const {return b_; }
If you left it like
B* get_b() const {return b_; }
you'd have the same problem.
Well, you have found the solution yourself.
boost::shared_ptr<const B> get_b() const { return b_; } // (1)
It's the only const-correct way to do it.