Reputation: 5104
At first, I was under the impression that member variables should usually be const in C++ classes, UNLESS i want it's member functions to modify those variables, internally for each object (the variables i usually put into private:).
but I now find out that i may have been wrong all along. e.g. i can't assign to such objects anymore. I can't even do move-assign.
Take say std::string. You can do this:
std::string foo("foo");
foo = std::string("bar");
this has to imply that internally, std::string has only non-const member variables right?
Is my thinking correct? Being relatively new to C++, it's new thinking is a bit strange. The purpose of const may not be what I thought it to be.
What's the ACTUAL PURPOSE of having const member variables then?
Upvotes: 3
Views: 2017
Reputation: 315
The C++ core guidelines (The C++ Core Guidelines are basically a set of tried-and-true guidelines, rules, and best practices about coding in C++ from the creators/maintainers of the language) says to not make data members const or references for exactly the problem you mentioned, that the class becomes non copy-assignable.
C.12: Don’t make data members const or references
Upvotes: 1
Reputation: 126432
Should members usually not be const in C++ classes?
I suggest you disregard how variable are declared "usually". The frequency of the occurrence of const
is not something that should make you decide whether the next variable you're going to declare is or is not const
.
Members should be const
if their value is not supposed to change after initialization throughout the execution of your program. Otherwise, they should not be const
. This is a semantic property of your data, and the only criterion you should use for deciding whether to make a variable const
or not is the nature of your variable with respect to value change.
May it change, or shall it stay unchanged? In the latter case, definitely do make it const
.
This has to imply that internally, std::string has only non-const member variables right?
No, it doesn't imply it, although that probably happens to be the case for std::string
.
The important thing is that there are not only const
members in your class (as long as you want to move from it and your class encapsulates some resource, of course), so that those members which actually can be used to tell whether an object has been moved from are modifiable.
When you move from an object, what you're left with is a skeleton. The move constructor or move assignment operator needs a way to "flag" this moved-from object as a skeleton. Normally, this follows naturally from the process of "stealing the guts" of the moved from object, i.e. copying some pointers and setting them to null - this way, the destructor and assignment operators won't try to release them. In order to flag the moved-from object as a "zombie", obviously you need some modifiable member variable(s).
However, there's nothing wrong with also having some const
members in your class. const
is an important modifier which makes the semantics of your program clearer, and your program less likely to break it. Whenever appropriate (i.e. whenever the value of A variable won't change throughout the execution of your program after initialization), use it.
Simply, const
member variables won't be modified by a move constructor or move assignment operator (in fact, they won't be modified by any function); but again, that doesn't mean they cannot be present.
Upvotes: 8
Reputation: 153919
It depends on the object, but in general, when you write the
code for an object, you are responsible for its invariants.
I rarely use const
or reference members, but they are
perfectly acceptable in classes which don't support assignment.
In general, const
is used as logical const, not bitwise const.
And const is more a contract between you and your clients,
rather than something to protect you against yourself. In this
sense, having const functions, returning const references, and
taking const references as arguments makes a lot of sense. Top
level const on an argument, or const in a class, doesn't really
mean much, however.
Upvotes: 2
Reputation: 51840
I was under the impression that member variables should usually be const in C++ classes, UNLESS i want it's member functions to modify those variables
What you're forgetting is that the assignment operator, including the default one, is a member function. Example:
struct Foo {
const int i = 0;
Foo& operator =(const Foo& src)
{
if (&src == this)
return *this;
i = src.i;
return *this;
}
};
Since the assignment operator is a member function, it obviously has to be able to modify Foo::i
. If not, you can't invoke it. Keep in mind that, given the Foo
objects a
and b
, this:
a = b;
is actually syntactic sugar for this:
a.operator= (b);
Also keep in mind that the default assignment operator gets deleted in this case, because Foo::i
is const
. That means that Foo
lacks an assignment operator altogether if you don't write one yourself.
Upvotes: 2
Reputation: 110658
The data members of a class describe the state of an object of that type. A const
data member implies that the objects have some state that never changes. This it not really very common. Often const
members are also static
.
The only thing you can do with a const
data member is initialise it the member initialization list of a constructor.
The fact that you can assign to a std::string
from another std::string
implies only that its copy assignment operator does not do anything to its const
data members (because of course it can't).
A class or struct that has a const
data member will not have an implicitly defaulted copy assignment operator. The compiler can't assign to your const
data member so it just says "If you want to assign, you'll have to define it yourself."
Upvotes: 0
Reputation: 298
I would start by suggesting you look at the answer to this related question.
The fast and dirty answer is that const member properties contain values which remain unchangeable AFTER the object is initialized. The copy operations are attempting to preform an action which causes a new object to be constructed and THEN have the values from the old object assigned to the new object(in the implicit copy constructor body). What you most likely would want as a solution is to make an explicit copy constructor, which takes the original object as an argument and INITIALIZES the const property values in the initialization list.
Example of a copy contructor:
ClassWithConstantProperties( const ClassWithConstantProperties &orig) :
constProperty1(orig.constProperty1)
constProperty2(orig.constProperty2)
{
}
This tutorial explains more fully the implicitly defined constructors of classes in C++, and is also on an excellent C++ reference page.
Upvotes: 1
Reputation: 57698
Constant variables are used when the value should not be changed inside the class after construction.
Some examples: numerical constants (pi, e) and references.
struct Database_Record
{
Database_Record(const std::string& table_name)
: m_table_name(table_name)
{ ; }
const std::string& get_table_name(void) const
{ return m_table_name; }
private:
const std::string m_table_name;
};
In the above structure representing a database record, it has a table name associated with the record, which cannot be change after intialization; this prevents the record from being written to the wrong table.
Upvotes: 0
Reputation: 2479
const objects are objects you dont want to change, they stay constant during the execution of the program. You can assign a value to them in the member initialization list of the constructor of your class but not beyond that. If you have a variable that can have different values, you should not use const.
Upvotes: 1