I have read about use cases of const and I feel like I have a good understanding of const for the most part. However, I can't seem to figure out why I don't see this more often:
void someFunction(const string& A) const
Where you have a const parameter in a const member function. For some reason, whenever I look up examples and the function is const, the const seems to be stripped off the parameters like this:
void someFunction(string& A) const
However that doesn't seem to stop me from modifying A. Is it considered bad form to have const parameters in a const member function?
What is the reasoning for not keeping the const in the parameters as well if A would not be modified?
EDIT: This is my fault for not clarifying but I understood the difference between adding it before the parameter and adding it after the function. A lot of code I looked at just never combined the two and I was just trying to figure out if there was a reason for that.
void someFunction(const string& A) const
The last const means that the method will not change the state of the object referenced by *this inside it. The first const is saying that the function will not change the state of the argument - and it doesn't have any correlation with the second const, so you may have this:
void someFunction(string& A) const
In this case function may change state of A argument, but it may not change the state of its object.
For example (and this is a highly hypothetical example):
class MyIntArray
{
// some magic here in order to implement this array
public:
void copy_to_vector(std::vector<int> &v) const
{
// copy data from this object into the vector.
// this will modify the vector, but not the
// current object.
}
}
And this is the example where these two are combined:
class MyOutput
{
char prefix;
// This class contains some char which
// will be used as prefix to all vectors passed to it
public:
MyOutput(char c):prefix(c){}
void output_to_cout(const std::vector<int> &i) const
{
// iterate trough vector (using const_iterator) and output each element
// prefixed with c - this will not change nor the vector
// nor the object.
}
}
Oh, and take a look into this question: Use of 'const' for function parameters
const on a function only applies to member functions. It states that the class object will not be modified. It does not mean that a function parameter passed by reference cannot be modified.
Passing a parameter to a function as const & prevents you from modifying the parameter.
class A
{
private:
int data;
public:
void func1(const std::string& s) const; // s cannot be modified, members of A cannot
void func2(std::string& s) const; // s can be modified, members of A cannot
void func3(const std::string& s); // s cannot be modified, members of A can be
void func4(std::string& s); // s can be modified, as can members of A
};
The functions labeled const cannot change data, but no such restriction is on s unless it is labeled const.
Related
This question already has answers here:
Meaning of 'const' last in a function declaration of a class?
(12 answers)
Use of 'const' for function parameters
(31 answers)
Closed 2 years ago.
I've seen the following:
void function_name(std::string& txt) const;
What is the purpose of the const in the above prototype? The return type of the function is void so there is no return type, it looks completely pointless to me, I've seen this a lot, also when passing in parameters like:
void function_name(const int a);
Why would const add anything to the above, it cannot be changed in the function anyway if its not a pointer or reference?
void function_name(std::string& txt) const;
const mostly means this is a const member function and it's not supposed to change the state of the object. So if the function changes any of the member variables it will lead to compile error.
For the second case:
void function_name(const int a);
This const means that the function is not suppose to change variable a in its function body. Note, however, that const would not be required for basic type like int or bool. Also it's most likely applied when pass-by-reference (not pass by value like this).
So a typical usage would more like this:
void function_name(const some_non_trival_type& a);
That's said it's okay in the beginning without const.
void function_name(const int a)
{
int b = 10;
// complex things ...
std::cout<< a+b;
}
One day someone thought a new line would magically increase the performance of the function
void function_name(const int a)
{
a = 10; // Beep! It doesn't compile.
int b = 10;
// complex things ...
std::cout<< a+b;
}
Then this const save the world before any unit tests have been executed.
I'd say this const might have a semantic meaning to tell others "don't modify it because this function works properly according to parameter's constness".
The const method prototype enables you to use such method also for const objects like:
struct X
{
void function_name(std::string& txt) const {}
};
int main()
{
const X x;
std::string s{"Hallo"};
x.function_name(s); // will not work if the function is not marked as const!
}
The second case
void function_name(const int a);
gives the compiler a hint that you will ( and can ) never change the content of the const variable. That allows the compiler to optimize it. If you use a non trivial object like:
void function_name(const XYZ x);
it makes more sense, because if it is not const, the compiler must create a full copy of the object for that function. That may also be optimized out, but in case of const there is simply no need to take a copy as nothing will be altered. By standard clever compilers the internal generated code can be equivalent to:
void function_name(const XYZ& x);
or
void function_name(XYZ& x);
For the given example of using an int, it is has more or less no effect, but clarifies the interface.
Basically I want to have a simple class that wrap a pointer (i.e. has a pointer member) and I don't know how to specify the constness of the constructor arguments. If I do this
class A {
public:
A(int *d) : data(d) {}
private:
int *data;
};
Then I can't do this
void func(const int *param) {
const A aInstance(param);
}
because the constructor doesn't take a const pointer.
I want to be able to construct const objects and take const pointers to do it, but I also want to be able to construct non-const objects that modify the pointer. How do I specify this class so that I can modify *data when it's relevant, but I can construct a const object what that is relevant?
Your constructor should take a pointer which points to a constant object:
A(const int *d) : data(d) {}
You have a key misconception here: The compiler is warning you that you're passing a pointer to a const int into an object which might try to change the int's value. Declaring const A doesn't fix that problem because, while data cannot change, the thing that data points to still can.
The solution you need has already been provided by others in the comments:
If A doesn't need to modify *data then you should declare it's member variable as const int *data.
Otherwise you'll need to provide two versions: A and const_A. You could type out two separate definitions or use templates so you only have to type it out once.
If you know that your usage is safe and you want to live dangerously then you could use const_cast to remove the constness and thwart the compiler's warning.
The only answer that seems to satisfactorily maybe answer the question is a comment from #JohnAuld who suggested I template the class thusly
template< typename data_t >
class A
{
public:
A(data_t *data) : d(data) {}
private:
data_t *d;
};
In theory this would work well to construct a constable object, and it even lets me create const and non-const methods for which compilation will fail if I try to assign something to the data pointed to by d for const objects. That's all fine and dandy. It even let's me do what I wanted:
void doSomething(const int *somePointer) {
A<const int> a(somePointer);
}
However, where it fails is to use const specifiers on the class. If I wanted to pass the subsequent const object to another function, it would fail:
void doSomethingToAnA(const A<int> &a);
void doSomethingToIntPointer(const int *aPointer) {
const A<int> aInstance(aPointer);
doSomethingToAnA(aInstance);//womp womp
}
basically const A<int> != A<const int>
If we have a function prototype like this :
const CString function(...)
{
CString x;
//do some stuff
return x;
}
does this mean that function returns a const CString ? because const in C++ can be placed in front of a method inside a class to tell the compiler that the attributes will not be modified (or not mutable)
I ask this "dumb" question, because in another case we can have something like this :
static CString function(...)
{ }
And in this case static relates to "function" and not to the variable returned.
In C++ const return_type function_name(params) means you have a function that returns a const return_type. If you have static return_type function_name(params) then this marks the function as static and you no longer need an instance of the class to call this function. If you want to mark a function as const meaning that it will not moodify the class contents then you need to place the const after the function as
return_type function_name(params) const
^^^^^
does this mean that function returns a const CString ?
Yes it does.
because const in C++ can be placed in front of a method inside a class to tell the compiler that the attributes will not be modified (or not mutable)
No it can't, the const has to be placed after the method to achieve that.
class MyClass {
// ...
const CString function();
// ...
}
A function returning const CString.
class MyClass {
// ...
CString const function();
// ...
}
Same thing.
class MyClass {
// ...
CString function() const;
// ...
}
A function that can be called on a constant object, as it "promises" not to change internal state.
As a rule of thumb, const is always after the thing declared constant...
...except for the old C-style const <type>, kept for backward compatibility.
The following two lines are the same thing, a constant pointer to a constant int. Note that to make the pointer constant, the const has to be trailing the *:
const int * const p1; // the exception
int const * const p2;
To return a const value from a function use :
const CString function(...)
{
CString x;
//do some stuff
return x;
}
To tell the compilater that attributes won't change use :
CString myClass::function(...) const
{
CString x;
//do some stuff
return x;
}
const CString function(...) returns a const CString,
but it is deprecated as rarely useful and by the fact that disallows move on the temporary. So, in CString s; s = foo();, a copy is done instead of a move.
The most significant usage was to forbid things like
foo() = CString(..);
C++11 introduces ref qualifier on method and r-value reference which allows to fix that differently:
Obj& operator = (const Obj& rhs) & ; // Note the final &
A function declared as const CString function(...) returns a const CString. This the the same in C++ as it is in C.
If you have a C++ method defined like this:
void MyClass::function(void) cont;
That means that the method function does not modify the object.
const appearing before the method describes the attributes of the return type of the method.
So,
const CString method_name();
means that the method returns a const CString object i.e. an object that cannot be modified by the caller of this method.
const appearing after the method describes the attributes of the method itself. It tells that the method does not "mutate" or "modify" the object it operates on.
So,
const CString method_name() const;
means that the method cannot modify any of the member variables of the object used to invoke the method. It has no relation with the return type of the method.
Let us see this with an example.
class Foo
{
int x;
int GetX() const {return x;}
void SetX(int i_x) {x = i_x;}
};
In the above class definition, GetX() is a const method i.e. it is not expected to modify the object which is used to invoke them. What does this mean? When you declare a class, there is a single version of each of the member functions which gets loaded onto memory. Further, all the non-static member methods need an object to invoke them. How is this achieved? When you declare a non-static member method of the class, the C++ compiler slyly changes the signature of the methods to expect a "this" pointer, that is the pointer to the object used to invoke the method.
For a non-const method, the type of the "this" pointer expected is Class*. So our SetX() method above looks like:
void SetX(Foo* this, int i_x) {this->x = i_x;}
You can use the this pointer to modify the object(x is part of the object right!)
However, for a const method, the type of the "this" pointer passed is
const Class* i.e. you cannot modify the object using the "this" pointer. So GetX becomes
int GetX(const Foo* this) {return this->x; }
Since the type of the this pointer is const Foo*, you cannot change the object the pointer points to i.e. you cannot do someething like:
x = 100;
which would translate to this->x = 100; which the compiler will complain about.
I have an a class which is singleton as defined follows
class myData {
private:
myData (void); // singleton class.
// Copy and assignment is prohibted.
myData (const myData &);
myData & operator=(const myData &);
static myData* s_pInstance;
public:
~myData (void);
static const myData & Instance();
static void Terminate();
void myFunc() { cout << "my function..." ;}
};
// In cpp file.
myData* myData::s_pInstance(NULL);
myData::myData(){}
myData::~myData()
{
s_pInstance = NULL;
}
const myData& myData::Instance()
{
if (s_pInstance == NULL)
{
s_pInstance = new myData();
}
return *(s_pInstance); // want to avoid pointer as user may deallocate it, so i used const referense
}
void main() {
(myData::Instance()).myFunc();
}
I am getting following error
error C2662: 'myData::myFunc' : cannot convert 'this' pointer from 'const myData' to 'myData&'
how to avoid above problem and call a function from Instance function which is returning const reference?
Thanks!
You'd want to declare func() as a constant member function, so the compiler knows it won't violate the const'd return value from the instance() function.
You could instead also make the instance() function return a 'regular' reference as apposed to a const one.
So either turn:
void myFunc() into void myFunc() const
Or turn:
const myData& myData::Instance() into myData& myData::Instance()
If you are calling a function on a const reference, the function you call must also be const, in your case void myFunc() const.
Otherwise you might return a non-const reference, if that works better.
The error says that myData::Instance() is a const instance of the class, and it can't call myFunc() on that, because myFunc() might change the instance, and you can't change a const instance.
Of course, you know that myFunc() can't really change the instance, but you must advertise this fact, as follows:
void myFunc() const { cout << "my function..." ;}
Avoiding the whole discussion of whether Singleton is a good to have pattern or the source of all evil, if you are actually implementing a singleton, chances are that const correctness will not work there as you expect it, so you should be aware of some pitfalls.
First your error: your Instance() static member returns a const reference, and that means that you can only perform operations that do not modify the object, i.e. call member functions marked as const, or use public members if present in a way that do not modify their values. My suggested solution is modify Instance() to return a non-const reference, rather than making func() const as others suggest.
Now for a longer explanation to the problem of const-correctness in general when applied to your particular Singleton problem. The basic problem is that when you implement a type, you divide those members that modify the object from those that don't, and you mark the latter as const member functions so that the compiler knows of your promise (allows you to call that method on a constant object) and helps you not break it (complains if you try to modify the state in the definition of the method). A method that is marked as const can be applied to both a constant and non constant object, but a method that is not marked const can only be applied to an object that is not const.
Back to the original piece of code, if you implement a singleton and the only way of accessing the object is by an Instance() method that returns a const reference, you are basically limiting all user code to use only const methods implemented in your interface. That means that effectively either all methods are non-mutating, or they are useless (const_cast should never be used). That in turn means that if you have any non-const operation you want to provide an Instance() method that returns a non-const reference.
You could consider implementing two variants of Instance(), but that will not be really helpful. Overload resolution will not help in user code to determine which version to use, so you will end up having to different methods: Instance(), ConstInstance() (choose your names), which means that it is up to user code to determine which one to use. The small advantage is that in their code, the choice of accessor will help documenting their intended usage, and maybe even catch some errors, but more often than not they will just call the non-const version because it works.
I have a function Foo and a class CDelegate.
typedef void (*typeFctPtr)(void*);
void Foo(void* dummy)
{
cout << "Foo\n";
}
class CDelegate
{
public:
CDelegate (const typeFctPtr& f_ref_Wrapper, void* f_pvSubscriber)
: m_ref_Wrapper(f_ref_Wrapper), m_pvSubscriber(f_pvSubscriber)
{
}
inline void operator () () const
{
(*m_ref_Wrapper)(0);
}
inline void operator=(const CInterruptDelegate& D)
{
}
private:
void* m_pvSubscriber;
const typeFctPtr& m_ref_Wrapper;
};
A second class has a static member static CDelegate m_Delegate; which I initialize using the constructor like this:
CInterruptDelegate CSpi1::m_Delegate(FreeFunction, 0);
I want to call Foo by calling the ()operator of my static object: CSpi1::m_Delegate();
I get an exception at (*m_ref_Wrapper)(0);
Is there something wrong with the syntax? I am not quite sure if what I try to do is possible at all. I have a working solution where the constructor of CDelegatedoes not take a const reference of a function pointer but the function pointer itself. I can then call the function in the ()operator without problems. I want to use a const reference because the function pointer call cannot be optimized and I hope the call via the const reference can because everything should be known at compile time.
You're holding a reference to a pointer to a function (and the pointer is a temporary which has been destroyed by the time you use it, so things go badly wrong).
Try changing your typedef to be a function type:
typedef void typeFct(void*);
...
const typeFct & m_ref_Wrapper;
Then with your existing code you'll end up with a reference to a function, and you'll be fine. Or you could store a pointer to the function - const typeFct *.
And in either case the call can just be m_ref_Wrapper(0).
In general I prefer to typedef function types rather than pointer-to or reference-to, if only because the syntax is less ugly.
I believe that the problem is the declaration of the member:
const typeFctPtr& m_ref_Wrapper;
Instead, try to drop the &:
const typeFctPtr m_ref_Wrapper;
A reference must always reference another existing object. In this case, it will refer the temporary object created to hold the reference to the pointer at the time the constructor is called.
While we're at it, I would suggest that you should drop the reference from the constructor as well. The reason for this is that there is no gain when you work with scalar:s.
Another thing that would make your code more readable is if you would typedef the type of the function, rather than the pointer to the function. That way, it would be clear that you pass around a pointer.
The following is a cut-down version that summarized the changes I suggest above:
typedef void (typeFct)(void*);
class CDelegate
{
public:
CDelegate (typeFct * f_Wrapper, void* f_pvSubscriber)
: m_ref_Wrapper(f_Wrapper), m_pvSubscriber(f_pvSubscriber)
{
}
inline void operator () () const
{
(*m_ref_Wrapper)(0);
}
private:
void* m_pvSubscriber;
typeFct * m_ref_Wrapper;
};