Suppose I have a class that has an array of pointers, and I have a method that dereferences a pointer and returns it as a reference. I want to allow the method caller to call non-const methods of the object the pointer is pointing to, but also want to protect myself from the caller changing what the pointer is pointing to. If I return a const reference, I have to mark many of the pointer object's methods as const, and hence many of its class member variables as mutable.
Is this bad practice? If so, how do I get around this?
Is there performance penalty for over-using mutable?
Example:
#include <iostream>
#include <array>
#include <memory>
class Counter
{
public:
Counter();
void hit() const;
void reset();
unsigned count() const;
private:
mutable unsigned count_;
};
Counter::Counter() : count_(0) {}
void Counter::hit() const { ++count_; }
void Counter::reset() { count_ = 0; }
unsigned Counter::count() const { return count_; }
class CircularArray
{
public:
CircularArray();
const Counter& next() const;
private:
mutable unsigned i_;
std::array<std::unique_ptr<Counter>, 3> arr_;
};
CircularArray::CircularArray() : i_(2)
{
arr_[0] = std::unique_ptr<Counter>(new Counter);
arr_[1] = std::unique_ptr<Counter>(new Counter);
arr_[2] = std::unique_ptr<Counter>(new Counter);
}
const Counter& CircularArray::next() const { return *arr_[(i_ = (i_ + 1) % 3)]; }
int main()
{
CircularArray circular;
const Counter* p;
p = &circular.next();
p->hit();
p->hit();
Counter c;
//*p = c; // <-- Want to prevent this
}
To extend what I was saying, there is no point in abusing mutable for this. If this is all you want to prevent:
*p = /* ... */;
then it can be done much more easily by deleting the assignment operator of Counter:
class Counter
{
void operator=(const Counter&) = delete;
// ...
};
Remember that the assignment operator does not affect the identity of the object: it doesn't change its address. Semantically, an assignment involving of modifying this object to replicate the state of another object. In fact, even if you forbid me from using the assignment operator somehow, I could still do this:
// a very inefficient way of performing `*p = c`
p->reset();
while (p->count() != c.count())
p->hit();
This achieves the exact same result as performing an assignment, albeit very clumsily and inefficiently.
Performing an assignment is no different than calling a non-const member function that accepts a single argument of type const Counter&. Hypothetically, you could redefine the assignment operator to do absolutely nothing at all if you wanted to (it would be a bad idea though).
Related
I was wondering if using the std::move() in this example is overkill or computationally more expensive than simply copying it? I would really like to know.
class Student
{
private:
std::string _studentName;
int _studentGrade;
public:
Student() : _studentName("No Name"), _studentGrade(0) {}
std::string Name() const { return _studentName; }
void Name(std::string x) { _studentName = std::move(x); }
int Grade() const { return _studentGrade; }
void Grade(int x) { _studentGrade = std::move(x); }
};
Reading the core guidelines at F.call: Parameter passing, we can deduce a few recommendations.
Use move only when you want to optimize for rvalue. If you find that it does an improvement on performance, it's up to you to do it.
You could receive by value then move as it optimises rvalues calls into your setters, but it pessimizes lvalues. This is because std::string will reuse its storage and not cause unnecessary allocations when copying from the const reference. Copying into the value parameter always end up allocating when no SSO is possible.
The preferred way, especially for setters are to use const reference, and add an rvalue reference overload when rvalues are passed into the setter:
class Student
{
private:
std::string _studentName;
int _studentGrade;
public:
Student() : _studentName("No Name"), _studentGrade(0) {}
std::string_view Name() const { return _studentName; }
void Name(std::string const& x) { _studentName = x; }
// add this when you need to optimize for rvalues.
// optimizing for rvalues is not always needed.
// They can speedup quite a bit when actually needed.
void Name(std::string&& x) { _studentName = std::move(x); }
// int is a trivial type, so move does nothing. No move needed.
int Grade() const { return _studentGrade; }
void Grade(int x) { _studentGrade = x; }
}
For the int, std::move won't do anything, it's still a copy. Just take them by value and return them by value.
However, the best you can do is much simpler:
class Student
{
public:
std::string studentName;
int studentGrade;
};
Since your setters don't enforce any invariants, you'd be better off using public members. You don't need overloads and reference since std::string implements it for you.
Given an immutable C++ object (its members are const, which means its operator=() method does not exist), how do you implement this simple procedural pattern (which would require Object::operator=() to exist):
Object someObject {17};
// ...
if (...) {
someObject = Object {42};
}
// ...
use(someObject);
A workaround is to use shared_ptr.
shared_ptr<Object> someObject(new Object(17));
shared_ptr<Object> anotherObject(new Object(42));
// ...
if (...) {
someObject = anotherObject;
}
use(someObject);
My pattern in such a situation is to extract initialization code into a function:
Object ini(...){
if(...) {
return Object{42};
}
return Object{17};
}
.....
Object someObject=ini(...);// copy constructor used (or not, because of RVO)
use(someObject);
If initialization is simple you could use:
Object someObject = ...? Object{42} : Object{17};
It is not very different to declaring your o-variable const.
If the someObject=17 is used and then replaced with someObject=42 - it's just undermining the good intentions which were pursued by declaring some members const.
There are two alternatives:
declaring some members const was not such bright idea - it can be undone and an assigment operator can be added.
using Object as it was meant to be used.
What should not be done lightly: making some tricks with pointers/references - it will just make your code more complex as it is. Better to use a new variable if needed:
Object someObject {17};
// ...
Object newSomeObject = ... ? Object {42} : someObject {17};
use(newSomeObject);
In the case that copying of the old object could be a performance problem, the code can be refactored in such a way, that
use(need42(..) ? create42() : object17);
can be used without copying data. This solution assumes that use uses a const reference of its argument or the parameter is passed by-value.
In my opinion every change of an immutable object should yield a new object, otherwise, the following can happen:
ImmutableObject obj(1);
ImmutableObject &ref=obj;//ref.member=1
...
obj=ImmutableObject(2);
//ref.member!=1, that is puzzling, I assumed ref to be immutable!
Now, the user of your object (via ref) gets irritated because the object was changed! The whole point of the immutability is that you can reason, that the values never ever change. If they can change, there is not that many advantages in using "immutables" in the first place.
The other answers work when your initialization logic may be simple, but if you're detangling some spaghetti code, this might help.
If it isn't, take from java (they might not have invented it, but I see java programmers use this most) -- the builder pattern. Here are two possible ways of implementing it in C++.
#include <string>
class ImmutableClass {
public:
ImmutableClass(int a, int b, std::string c) : a_(a), b_(b), c_(c) {}
// Getters...
private:
ImmutableClass& operator=(const ImmutableClass&) = delete;
const int& GetA() {return a_;}
const int& GetB() {return b_;}
const std::string& GetC() {return c_;}
const int a_;
const int b_;
const std::string c_;
};
struct ImmutableClassBuilderExampleOne {
public:
// Note the default initialization to avoid undefined behavior.
int a = 0;
int b = 0;
std::string c;
};
// Less boilerplate, less encapsulation, if that's your thing.
ImmutableClass BuildImmutableClass(const ImmutableClassBuilderExampleOne& icb) {
return ImmutableClass(icb.a, icb.b, icb.c);
}
// More boilerplate, more encapsulation, can be "tidied" with macros.
class ImmutableClassBuilderExampleTwo {
public:
const ImmutableClass build() {
return ImmutableClass(a_, b_, c_);
}
ImmutableClassBuilderExampleTwo& setA(const int a) {
a_ = a;
return *this;
}
ImmutableClassBuilderExampleTwo& setB(const int b) {
b_ = b;
return *this;
}
ImmutableClassBuilderExampleTwo& setC(const std::string& c) {
c_ = c;
return *this;
}
private:
// Note the default initialization to avoid undefined behavior.
int a_ = 0;
int b_ = 0;
std::string c_;
};
Say I have a simple class like this
class Foo
{
public:
void foo()const
{
str[5] = 'x';
obj->changeTheWorld();
x = 4;
y.get() = 5;
obj2->changeTheWorld();
}
private:
char *str; //some referenced data, not owned by Foo
ComplexObj *obj; //some referenced data, not owned by Foo
int &x; //references as well
//wrapped reference, but has a "T& get()const"
std::reference_wrapper<int> y;
//an occasionally useful pointer wrapper for complex memory cases
//but has a "T* get()const"
std::shared_ptr<ComplexObj> obj2;
};
This is valid because in the const method, its just the pointer itself that becomes const, not the data it points to. However in many cases that is not what I desired and I want a compile error if a const method tries to change these members contents (either directly or by calling a non-const method on that member).
Is there a standard solution to this?
I think some kind of wrapper class should be able to achieve this, and should also be something the compiler optimises out, although haven't sat down to try and design such a thing to cover all cases giving say a strong_const<char*> str and strong_const<int&> (also not sure on a good name...).
Well, neither std::reference_wrapper nor std::shared_ptr do not provide const propagation, so they are not more "const-strict" than regular pointer.
I'd recommend to make your own const propagation class (I am not sure - maybe something similar is already provided by boost - please let me know in comments)
My proposition is this class:
#include <memory> // for pointer_traits
template <typename Pointer>
class ConstPropagatePointer
{
public:
using element_type = typename std::pointer_traits<Pointer>::element_type;
using pointer = typename std::pointer_traits<Pointer>::pointer;
using const_pointer = element_type const * const;
using reference = element_type&;
using const_reference = element_type const&;
ConstPropagatePointer(Pointer ptr) : ptr(ptr) {}
pointer operator -> ()
{
return &(*ptr);
}
const_pointer operator -> () const
{
return &(*ptr);
}
reference operator * ()
{
return *ptr;
}
const_reference operator * () const
{
return *ptr;
}
private:
Pointer ptr;
};
So that will work for you:
class Foo
{
public:
private:
ConstPropagatedPointer<char*> str;
ConstPropagatedPointer<ComplexObj*> obj;
ConstPropagatedPointer<std::shared_ptr<ComplexObj>> obj2;
};
This question already has answers here:
When should I make explicit use of the `this` pointer?
(12 answers)
Closed 6 years ago.
What is purpose of this keyword. Doesn't the methods in a class have access to other peer members in the same class ? What is the need to call a this to call peer methods inside a class?
Two main uses:
To pass *this or this as a parameter to other, non-class methods.
void do_something_to_a_foo(Foo *foo_instance);
void Foo::DoSomething()
{
do_something_to_a_foo(this);
}
To allow you to remove ambiguities between member variables and function parameters. This is common in constructors.
MessageBox::MessageBox(const string& message)
{
this->message = message;
}
(Although an initialization list is usually preferable to assignment in this particular example.)
Helps in disambiguating variables.
Pass yourself as a parameter or return yourself as a result
Example:
struct A
{
void test(int x)
{
this->x = x; // Disambiguate. Show shadowed variable.
}
A& operator=(A const& copy)
{
x = copy.x;
return *this; // return a reference to self
}
bool operator==(A const& rhs) const
{
return isEqual(*this, rhs); // Pass yourself as parameter.
// Bad example but you can see what I mean.
}
private:
int x;
};
Consider the case when a parameter has the same name as a class member:
void setData(int data){
this->data = data;
}
Resolve ambgiguity between member variables/functions and those defined at other scopes
Make explicit to a reader of the code that a member function is being called or a member variable is being referenced.
Trigger IntelliSense in the IDE (though that may just be me).
The expression *this is commonly used to return the current object from a member function:
return *this;
The this pointer is also used to guard against self-reference:
if (&Object != this) {
// do not execute in cases of self-reference
It lets you pass the current object to another function:
class Foo;
void FooHandler(Foo *foo);
class Foo
{
HandleThis()
{
FooHandler(this);
}
};
Some points to be kept in mind
This pointer stores the address of
the class instance, to enable pointer
access of the members to the member
functions of the class.
This pointer is not counted for
calculating the size of the object.
This pointers are not accessible for
static member functions.
This pointers are not modifiable
Look at the following example to understand how to use the 'this' pointer explained in this C++ Tutorial.
class this_pointer_example // class for explaining C++ tutorial
{
int data1;
public:
//Function using this pointer for C++ Tutorial
int getdata()
{
return this->data1;
}
//Function without using this pointer
void setdata(int newval)
{
data1 = newval;
}
};
Thus, a member function can gain the access of data member by either using this pointer or not.
Also read this to understand some other basic things about this pointer
It allows you to get around members being shadowed by method arguments or local variables.
The this pointer inside a class is a reference to itself. It's needed for example in this case:
class YourClass
{
private:
int number;
public:
YourClass(int number)
{
this->number = number;
}
}
(while this would have been better done with an initialization list, this serves for demonstration)
In this case you have 2 variables with the same name
The class private "number"
And constructor parameter "number"
Using this->number, you let the compiler know you're assigning to the class-private variable.
For example if you write an operator=() you must check for self assignment.
class C {
public:
const C& operator=(const C& rhs)
{
if(this==&rhs) // <-- check for self assignment before anything
return *this;
// algorithm of assignment here
return *this; // <- return a reference to yourself
}
};
The this pointer is a way to access the current instance of particular object. It can be used for several purposes:
as instance identity representation (for example in comparison to other instances)
for data members vs. local variables disambiguation
to pass the current instance to external objects
to cast the current instance to different type
One more purpose is to chaining object:
Consider the following class:
class Calc{
private:
int m_value;
public:
Calc() { m_value = 0; }
void add(int value) { m_value += value; }
void sub(int value) { m_value -= value; }
void mult(int value) { m_value *= value; }
int getValue() { return m_value; }
};
If you wanted to add 5, subtract 3, and multiply by 4, you’d have to do this:
#include
int main()
{
Calc calc;
calc.add(5); // returns void
calc.sub(3); // returns void
calc.mult(4); // returns void
std::cout << calc.getValue() << '\n';
return 0;
}
However, if we make each function return *this, we can chain the calls together. Here is the new version of Calc with “chainable” functions:
class Calc
{
private:
int m_value;
public:
Calc() { m_value = 0; }
Calc& add(int value) { m_value += value; return *this; }
Calc& sub(int value) { m_value -= value; return *this; }
Calc& mult(int value) { m_value *= value; return *this; }
int getValue() { return m_value; }
};
Note that add(), sub() and mult() are now returning *this. Consequently, this allows us to do the following:
#include <iostream>
int main()
{
Calc calc;
calc.add(5).sub(3).mult(4);
std::cout << calc.getValue() << '\n';
return 0;
}
We have effectively condensed three lines into one expression.
Copied from :http://www.learncpp.com/cpp-tutorial/8-8-the-hidden-this-pointer/
Sometimes you want to directly have a reference to the current object, in order to pass it along to other methods or to store it for later use.
In addition, method calls always take place against an object. When you call a method within another method in the current object, is is equivalent to writing this->methodName()
You can also use this to access a member rather than a variable or argument name that "hides" it, but it is (IMHO) bad practice to hide a name. For instance:
void C::setX(int x)
{
this->x = x;
}
For clarity, or to resolve ambiguity when a local variable or parameter has the same name as a member variable.
It also allows you to test for self assignment in assignment operator overloads:
Object & operator=(const Object & rhs) {
if (&rhs != this) {
// do assignment
}
return *this;
}
It also allows objects to delete themselves. This is used in smart pointers implementation, COM programming and (I think) XPCOM.
The code looks like this (excerpt from some larger code):
class counted_ptr
{
private:
counted_ptr(const counted_ptr&);
void operator =(const counted_ptr&);
raw_ptr_type _ptr;
volatile unsigned int _refcount;
delete_function _deleter;
public:
counted_ptr(raw_ptr_type const ptr, delete_function deleter)
: _ptr(ptr), _refcount(1), _deleter(deleter) {}
~counted_ptr() { (*_deleter)(_ptr); }
unsigned int addref() { return ++_refcount; }
unsigned int release()
{
unsigned int retval = --_refcount;
if(0 == retval)
>>>>>>>> delete this;
return retval;
}
raw_ptr_type get() { return _ptr; }
};
The double colon in c++ is technically known as "Unary Scope resolution operator".
Basically it is used when we have the same variable repeated for example inside our "main" function (where our variable will be called local variable) and outside main (where the variable is called a global variable).
C++ will alwaysexecute the inner variable ( that is the local one).
So imagine you want to use the global variable "Conundrum" instead the local one just because the global one is expressed as a float instead of as an integer:
#include <iostream>
using namespace std;
float Conundrum=.75;
int main()
{
int Conundrum =75;
cout<<::Conundrum;
}
So in this case the program will use our float Conundrum instead of the int Conundrum.
Edit1: I realize this is hard to understand this question without having an insight of what I'm trying to do. The class A is not complete but it essentially stand for a C-array "proxy" (or "viewer" or "sampler"). One interesting usage is too present a C-array as a 2d grid (the relevant function are not shown here). The property of this class are the following:
it should not own the data - no deep copyy
it should be copyable/assignable
it should be lightweight (
it should preserve constness (I'm having trouble with this one)
Please do not question the purpose or the design: they are the hypothesis of the question.
First some code:
class A
{
private:
float* m_pt;
public:
A(float* pt)
:m_pt(pt)
{}
const float* get() const
{
return m_pt;
}
void set(float pt)
{
*m_pt = pt;
}
};
void gfi()
{
float value = 1.0f;
const A ac(&value);
std::cout<<(*ac.get())<<std::endl;
A a = ac;
a.set(2.0f);
std::cout<<(*ac.get())<<std::endl;
}
Calling "gfi" generate the following output:
1
2
Assigning a with ac is a cheap way to shortcut the constness of ac.
Is there a better way to protect the value which m_pt point at?
Note that I DO want my class to be copyable/assignable, I just don't want it to loose its constness in the process.
Edit0: I also DO want to have a pointer in there, and no deep copy please (let say the pointer can be a gigantic array).
Edit2: thanks to the answers, I came to the conclusion that a "const constructor" would be a useful thing to have (at least in this context). I looked it up and of course I'm not the same one who reached this conclusion. Here's an interesting discussion:
http://www.rhinocerus.net/forum/language-c-moderated/569757-const-constructor.html
Edit3: Finally got something which I'm happy with. Thanks for your help. Further feedback is more than welcome
template<typename T>
class proxy
{
public:
typedef T elem_t;
typedef typename boost::remove_const<T>::type elem_unconst_t;
typedef typename boost::add_const<T>::type elem_const_t;
public:
elem_t* m_data;
public:
proxy(elem_t* data = 0)
:m_data(data)
{}
operator proxy<elem_const_t>()
{
return proxy<elem_const_t>(m_data);
}
}; // end of class proxy
void test()
{
int i = 3;
proxy<int> a(&i);
proxy<int> b(&i);
proxy<const int> ac(&i);
proxy<const int> bc(&i);
proxy<const int> cc = a;
a=b;
ac=bc;
ac=a;
//a=ac; // error C2679: binary '=' : no operator found which takes a right-hand operand of type...
//ac.m_data[0]=2; // error C3892: 'ac' : you cannot assign to a variable that is const
a.m_data[0]=2;
}
Your class is badly designed:
it should use float values, not pointers
if you want to use pointers, you probably need to allocate them dynamically
and then you need to give your class a copy constructor and assignment operator (and a destructor) , which will solve the problem
Alternatively, you should prevent copying and assignment by making the copy constructor and assignment op private and then not implementing them.
You can trick around with proxy pattern and additional run-time constness boolean member. But first, please tell us why.
Effectively your class is like an iterator that can only see one value. It does not encapsulate your data just points to it.
The problem you are facing has been solved for iterators you should read some documentation on creating your own iterator and const_iterator pairs to see how to do this.
Note: in general a const iterator is an iterator that cannot be incremented/decremented but can change the value it points to. Where as a const_iterator is a different class that can be incremented/decremented but the value it points to cannot be changed.
This is the same as the difference between const float * and float *const. In your case A is the same as float * and const A is the same as float *const.
To me your choices seem to be:
Encapsulate your data.
Create a separate const_A class like iterators do
Create your own copy constructor that does not allow copies of const A eg with a signature of A(A & a);
EDIT: considering this question some more, I think you are misinterpreting the effect of const-correctness on member pointers. Consider the following surprising example:
//--------------------------------------------------------------------------------
class CNotSoConstPointer
{
float *mp_value;
public:
CNotSoConstPointer(float *ip_value) : mp_value(ip_value) {}
void ModifyWithConst(float i_value) const
{
mp_value[0] = i_value;
}
float GetValue() const
{
return mp_value[0];
}
};
//--------------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
float value = 12;
const CNotSoConstPointer b(&value);
std::cout << b.GetValue() << std::endl;
b.ModifyWithConst(15);
std::cout << b.GetValue() << std::endl;
while(!_kbhit()) {}
return 0;
}
This will output 12 and then 15, without ever being "clever" about the const-correctness of the const not-so-const object. The reason is that only the pointer ITSELF is const, not the memory it points to.
If the latter is what you want, you'll need a lot more wrapping to get the behavior you want, like in my original suggestion below or Iain suggestion.
ORIGINAL ANSWER:
You could create a template for your array-proxy, specialized on const-arrays for the const version. The specialized version would have a const *m_pt, return a const pointer, throw an error when you try to set, and so on.
Edit: Something like this:
template<typename T>
class TProxy
{
T m_value;
public:
TProxy(T i_t) : m_value(i_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.m_value) {}
T get() { return m_value; }
void set(T i_t) { m_value = i_t; }
};
template<typename T>
class TProxy<const T *>
{
const T *mp_value;
public:
TProxy(const T *ip_t) : mp_value(ip_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.mp_value) {}
T get() { return m_value; }
};
Why not replace float* with float in A. If you don't either the original owner of the float that the float* references can change it, or anyone prepared to do a mutable cast on the return value from a::get.
const is always just a hint to the compiler; there are no ways to make a variable permanently read-only.
I think you should use deep copy and define your own assingment operator and copy constructor.
Also to return handle to internal data structure in not a good practice.
You can deny the copy-constructor for certain combinations of arguments:
For instance, adding the constructor;
A(A& a) :m_pt(a.m_pt) { m_pt = a.m_pt; }
prevents any instance of A being initialised with a const A.
This also prevents const A a2 = a1 where a1 is const, but you should never need to do this anyway, since you can just use a1 directly - it's const even if you could make a copy, a2 would be forever identical to a1.