For the code below:
class Foo {
private:
int var;
int* var_ptr;
public:
Foo() : var_ptr(&var), var_ptr_ref(var_ptr) {}
int*& var_ptr_ref; // Read only access to var and var_ptr
};
Is it possible to make the pointer const and the actual variable constant when accessed via var_ptr_ref?
Try declaring var_ptr as const int and var_ptr_ref as const int * const &:
class Foo {
private:
int var;
const int * var_ptr;
public:
Foo() : var_ptr(&var), var_ptr_ref(var_ptr) {}
const int * const & var_ptr_ref;
};
Related
Following example shows the crux of the problem. I need to initialize const members of a class. This can only be done in the initializer-list and not in constructor body. I want to assert or throw an error if input to the constructor is invalid, that is, if the vector size is less than 3.
class A {
// In following constructor, how do we make sure if params.size()
// is at least 3.
A(const std::vector<int>& params):
x(params[0]), y(params[1]), z(params[2]) {}
private:
const int x;
const int y;
const int z;
};
Please advise how to achieve this in Modern C++ (11 and later)
Just add a layer of abstraction. You can write a function that makes sure the vector is of the correct size and you can even make sure the values are in an expected range, if you have one. That would look like
class A {
A(const std::vector<int>& params):
x(verify(params, 0)), y(verify(params, 1)), z(verify(params, 3)) {}
private:
static int verify(const std::vector<int>& params, int index)
{
if (params.size() < 4) // or use if (params.size() <= index) if you only care if the index will work
throw something;
return params[index];
}
const int x;
const int y;
const int z;
};
const members can only be initialized in the constructors's member initialization list. To validate the caller's input, you would have to call a helper function to validate each input value before passing it to the corresponding member, eg:
int check(const std::vector<int> ¶ms, int index) {
if (params.size() <= index) throw std::length_error("");
return params[index];
}
class A {
A(const std::vector<int>& params):
x(check(params, 0)), y(check(params, 1)), z(check(params, 3)) {}
private:
const int x;
const int y;
const int z;
};
Or, simply utilize the vector's own built-in bounds checking instead:
class A {
A(const std::vector<int>& params):
x(params.at(0)), y(params.at(1)), z(params.at(3)) {}
private:
const int x;
const int y;
const int z;
};
Not as elegant as other solutions but... you can simply add a throw in a ternary operator inside the initialization of the first constant
class A
{
private:
const int x;
const int y;
const int z;
public:
A (const std::vector<int>& params)
: x{ params.size() < 4u ? throw std::runtime_error{"!"}
: params[0] },
y{params[1]}, z{params[3]}
{ }
};
Off Topic suggestion: if A is a class, maybe it's better that the constructor is public.
Other option extra layer through conversion:
class A_params{
friend class A;
int x;
int y;
int z;
void validate();
public:
A_params(std::initializer_list<int>);
A_params(const std::vector<int>&);
A_params(int(&)[3]);
//...
};
class A {
// In following constructor, how do we make sure if params.size()
// is at least 3.
public:
A(A_params params):
x(params.x), y(params.y), z(params.z) {}
private:
const int x;
const int y;
const int z;
};
in C++ is it a bad practice to use reference in place of getters?
for example:
class X
{
int mP;
public:
const int& P;
X():P(mP){}
};
and later
X xl;
int h = xl.P;
Just think about refactoring to make the access thread safe, that won't work well this way and require a lot of changes in the client classes/functions.
If you have class members, that are guaranteed not to be changed over lifetime of the instance, you can simply provide const int P; and initialize it properly in your class' constructors.
If the value is to be visible class wide use a static const int P;
In any other case use a public getter:
int P() const; // a return type of 'const int &' would be redundant
1st shot implementation:
int X::P() const
{
return mP;
}
Thread safe implementation:
class X {
{
// ...
private:
// ...
mutable std::mutex internalDataGuard;
};
int X::P() const
{
std::lock(internalDataGuard);
return mP;
}
None of this is good:
class X { public: int x; };
class X {
private: int m_x;
public: const int& get() const { return m_x; }
public: void set(const int& other) { m_x = other; }
};
class X {
private: int m_x;
public: const int& x() const { return m_x; }
public: void x(const int& other) { m_x = other; }
};
class X {
private: int m_x;
public: const int& x() const { return m_x; }
public: int& x() { return m_x; }
};
Pick one, it's a design decision.
Having 'const int& x' to publish the private member will work:
class X {
private: int m_x;
public: const int& x;
public: X() : m_x(0), x(m_x) {}
// Take care for copy and assignment
};
The cost is a larger memory footprint.
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 };
In one of our text-books it is suggested that we should use interfaces in C++ as a good design practice. They give below example;
class IAnimation
{
public:
virtual void VAdvance(const int deltaMilisec) = 0;
virtual bool const VAtEnd() const = 0;
virtual int const VGetPostition() const = 0;
};
I did not get the meaning of:
virtual bool const VAtEnd() const = 0;
virtual int const VGetPostition() const = 0;
I know const is used after () to make them invocable from const instances. But what const before VAtEnd and VGetPosition (method names) mean?
Thank you.
It means the return type is const, it's the same as:
virtual const bool VAtEnd() const = 0;
virtual const int VGetPostition() const = 0;
It has no practical meaning though, as the return value is copied anyway.
If you'd be returning an object though:
struct A
{
void goo() {}
};
const A foo() {return A();}
int main()
{
A x = foo();
x.goo(); //ok
foo().goo(); //error
}
struct Foo {
char * DataPtr;
};
class ISomeInterface {
public:
Foo GetFoo( ) const;
Foo GetFoo( );
};
The Foo::DataPtr is a pointer to an internal buffer of the object behing ISomeInterface. Is there a way to make sure that the Foo::DataPtr returned by the const version of ISomeInterface::GetFoo is a const char * ?
You need a
struct ConstFoo {
const char* DataPtr;
};
for this. The const in C++ is not transitive. (this is also why you have iterator and const_iterator.)
A struct
struct Foo {
char * DataPtr;
}
is not the same as
struct Foo {
const char * DataPtr;
}
so you cannot differentiate how you would like.
You could make the const GetFoo() return a const Foo object (which I suspect is not what you want, as it will make all the member variables const), or make another struct with a const char * DataPtr (say FooConst) which is returned on the const call.
You could try to change the design of your Foo and 'hide' the acess to DataPtr behind functions. For instance:
class Foo {
char * DataPtr;
public:
//just some examples
void doThis() const {}
void doThat() {}
};
class ISomeInterface {
public:
const Foo GetFoo( ) const { return Foo(); }
Foo GetFoo( ) { return Foo(); }
};
...
const Foo foo1 = ISomeInterface().GetFoo();
foo1.doThis();
foo1.doThat(); //error
Foo foo2 = ISomeInterface().GetFoo();
foo2.doThis();
foo2.doThat();
Providing functions that define which operations are const and those that are not you can avoid duplicating your Foo and obtain the const-correctness restrictions you seem to be aiming for.