c++ nonconst-const-overloaded method choosing - c++

I have const-overloaded methods in my class:
class A{
public:
typedef int data[10];
data& operator[](int index);
const data& operator[](int index) const;
}
This class is implementing copy-on-write for its internal data. I figured that since i am allowing to access data directly, i must create copy of shared data (if it is shared obviously) on every use of operator[], but not operator[] const. However, even if code is using operator[] for reading data, but object itself is not declared as const, it will still cause creating copy, as operator[] will be used. Is there any syntax that would let me allow to choose which of those operators i am calling?

Yes: const_cast<A const&>(anAObj)[5].

Why does the operator return a data& rather than an int& that references a single item?
That being said your options include:
Always do the copy even if it turns out to be unneeded.
Use the operator for read or write, and a named method (GetRef for example) for the other one.
Cast the object to const at the use point: static_cast<const A&>(obj)[index].

You need to create a Proxy class to substitute the return value of both methods. Then, in the Proxy class you can handle reads and writes appropriately. Here's code that should compile to demonstrate the idea (working with an array of unsigned integers):
typedef unsigned int UINT;
class A {
class Proxy {
public:
Proxy(const UINT &number): _number(number) {}
const Proxy &operator=(const Proxy &obj) {
cout << "Writting...\n";
_number = obj._number;
return *this;
}
operator const UINT &() const {
cout << "Reading...\n";
return _number;
}
private:
UINT _number;
};
public:
A(UINT *array): _array(array) {}
Proxy operator[](int index) {
return _array[index];
}
const Proxy operator[](int index) const {
return _array[index];
}
private:
UINT *_array;
};
int main(int argc, char** argv) {
UINT myArray[] = {0, 1, 2, 3, 4};
A a(myArray); // Normal A object
UINT num1 = a[1]; // Reading fine
a[1] = num1; // Writting fine
const A ca(myArray); // Constant A object
UINT num2 = ca[1]; // Reading fine
ca[1] = num2; // Writting NOT fine (compilation error)
return 0;
}

implement data& at(size_t i); and const data& cat(size_t); functions, so you can invoke cat() on non-const objects to enforce constness of returned data.

No, unless you cast the reference/pointer to a constant. Or create a constant copy.
A a;
const_cast<const A &> (a)[0] /*.foo ()*/;

If you are implementing copy-on-write, then you should not define those subscription operators at all. A client that calls the const version of the subscription method for an object x is not allowed to subsequently use that reference to modify a component of x, but the reference should still reflect the changes that other clients make to (that component of) x. But his is not going to happen with a copy-on-write strategy, since the change will happen in a different copy than the reference points to.
Also two clients that call the non-const subscription operator with the same index should get (modifyable) references to the same data object; but they won't, because two seperate copies will have been made when the subscription operators were called.
Instead you could have a subscription method that returns data by value. This avoids creating the illusion of obtaining an alias for a component of x (which as I argued must be illusory when copy-on-write is implemented). You could also provide a single method that modifies a component of x (rather than splitting this operation into a subscription followed by assignment to the reference so obtained), which would either internally make a copy, or just modify a component in place if this copy was already made. This would hide from clients the use of a copy-on-write implementation.
More generally, exposing methods that return references to internal objects, whether const or not, is exposing the implementation detail that such objects exist at all. This limits the freedom of changing the implementation later, for instance to compress the data or to store it elsewhere than in memory.

Related

Is this approach for const pointers okay?

I want to provide different levels of const 'access' to my data. For example, depending on whether the pointer or data should be modified. So this is what I came up with:
class MyClass
{
int n;
int* ptr_to_data;
int* const const_ptr_to_data;
const int * ptr_to_const_data;
public:
MyClass(int nn)
: n(nn),
ptr_to_data(&n),
const_ptr_to_data(ptr_to_data),
ptr_to_const_data(ptr_to_data)
{
}
~MyClass() { }
int& get_data()
{
return *const_ptr_to_data;
}
const int& get_data() const
{
return *ptr_to_const_data;
}
};
The goal here is to avoid programmer errors by restricting as much access as possible. Is this a good approach, how to make it better?
You have the correct approach with the two get_data functions, but all the pointers just make the code harder to maintain. Just this is sufficient:
int& get_data() { return n; }
const int& get_data() const { return n; }
The pointers you store don't help with the access problem, as you'll see, but they will refer to data in the wrong instance when you copy an object, unless you take charge of copying. And the top level const prevents assignment for class instances. I.e. the pointers are problematic, and do not contribute any advantage.
Instead do this:
int data() const
{
return n_;
}
void set_data( int const value )
{
n_ = value;
}
Or you might do as in the standard library and name also the setter just data, but the imperative form is more readable in the calling code.
A key feature of this approach is not pass out a pointer or reference to non-const data member.
Because by passing out unrestricted reference or pointer you lose all control over changes to that data member, in particular with respect to maintaining a class invariant, possibly other related values, imposing range restrictions, checking when changes are made, and so on.

Array Subscription: returning Reference vs proxy class method

While searching for methods for overloading Subscript('[]') operator for template class, I came across two different techniques.
First Technique:
Overloading the operator [] returning pointer to the container directly, which will allow both reading value and assigning value. A sample implementation of this technique:
template <class T>
class X
{
int _size;
T *container;
public:
X(int sz)
{
_size=sz;
container=new T[sz]();
}
~X()
{
}
T& operator [](int indx)
{
return container[indx];
}
};
With main() as:
X<int> sample(100);
cout<<sample[9]<<endl;
sample[9]=9;
cout<<sample[9]<<endl;
Output:
0
9
Second Technique:
Second technique involves declaring a proxy class and overloading the operator = via that class. A sample implementation of this technique:
template <class T>
class X
{
int _size;
T *container;
public:
X(int sz)
{
_size=sz;
container=new T[sz]();
}
~X()
{
}
class Proxy
{
int indx;
X<T> &parent;
public:
Proxy(X<T> &p, int x) : parent(p),indx(x)
{
}
void operator =(T assgn)
{
parent.container[indx]=assgn;
}
operator T const &()
{
return parent.container[indx];
}
friend class X<T>;//unnecessary line, I know!
};
Proxy operator[](int indx)
{
return Proxy(*this,indx);
}
};
With same main() we get same output.
I personally like the second method. But, I really want to compare these two methods. What are the major functional difference of these two techniques. What advantages each of these method have?
The proxy-based technique you describe can be used if you want to expose a sequence of elements that are not stored as-such (requiring a conversion from and to storage) or that cannot simply be accessed by-reference. An example is std::vector < bool >: it packs eight bools in every byte (one in each bit) in storage. Storing them that way, it is not possible to return a reference to a single such bool, so the index operator returns a "proxy-object" instead to support reading and writing of the contained bools.
If you can return a direct reference to the stored objects, there is no real advantage to wrapping it in a proxy unless you want to restrict the assignment (only allow positive values in the container for example).
Usually, a proxy is used when you want to return something that doesn't match the internal storage of the data. The classic example is a 2D matrix, with elements stored in a single array. If you provide an operator to return rows or columns, you need proxies. Another example is the infamous std::vector<bool>, where the data need not be stored as a block of bool, but access must return bool to the user.
Proxies can be used to return different "views" of segments of an internal data representation. In your example, there seems no reason to use them.
Getting proxy objects right for most client usage is considerably trickier... for example - what if someone says:
tcp_peer.send_from_iterator_range(&sample[2], &sample[7+1]);
If sample::operator[] returns a temporary proxy, and that proxy doesn't carefully replace operator&, then the code asks for the addresses of the proxies themselves.
Some client usage just can't be supported without losing the Proxy's ability to intercept reads and/or writes to the data, for example in...
Container::element_type& ref = container[n];
ref = 20;
...the client code assumes the container's operator[] will yield a reference to an actual element. Any proxy returned by operator[] must either provide an operator element_type&() - handing over such a reference and taking itself out of play - or refuse to (e.g. only return a const reference, return a temporary by value to which a non-const reference can't be bound) and force edits to the client code.
So, proxy's are 95% as good when you need them, but best avoided when you don't.

Preserve constness on assigning an object

Is it possible to preserve constness of an object when assigning? Consider a class holding pointer to dynamic memory, a soft copy is expected on assignment. (There is some more complex logic including reference counting, but it is not relevant for the question).
class Vec {
private:
int *data_; // dynamic array
public:
int * Data() { return data_;} // access for modification
const int * Data() const { return data_;} // read only access
Vec subVec(int pos) { // create writable submat
Vec ret;
ret.data_ = &data_[pos];
return ret;
}
const Vec subVec(int pos) const { // create read only submat
Vec ret;
ret.data_ = &data_[pos];
return ret;
}
};
void processVec(const Vec & src) {
src.Data()[0] = 1; // not allowed, since src const
Vec subVec = src.subVec(2); // call const version of subVec and create
// a soft copy - wrapper for a part of array.
// Assignment creates a copy, which removes constness
subVec.Data()[0] = 1; // allowed! Since subVec is a copy, but modifies
// identical dynamic memory from the wrapped src!
}
I would like subVec.Data()[0] = 1; to fail, since it is supposed to remain const.
Your problem is, that you are defining a smart pointer to some object, but you confuse constness of the smart pointer (the analogue to Foo* const bar;) with constness of the object (the analogue to const Foo* bar;). What you need, is to separate the constness of the pointer from the constness of the object.
You can relatively easily do so by using two smart pointer classes instead of one: A base class, that implements the smart pointer for a const object, and a derived class that implements the smart pointer for a non-const object.
With that, you can always demote your smart pointers to the "const" base class, make copy free "const" copies, etc. You might even add a constructor to the derived, non-"const" smart pointer class that takes a smart pointer of the "const" base class to make a deep copy of the data.
I would mimic the iterator and const_iterator idiom by creating a different return type when working with const or non-const object. Here an example implementing just a different type for const call to subVec:
class Vec {
// ...
public:
// ...
const int * Data() const { return data_;} // read only access
Vec subVec(int pos) { // create writable submat
Vec ret;
ret.data_ = &data_[pos];
return ret;
}
class SubVec
{
private:
const int* data_;
public:
SubVec(const int* data) : data_(data) {}
const int * Data() const { return data_;} // read only access
};
const SubVec subVec(int pos) const { // create read only submat
SubVec ret(&data_[pos]);
return ret;
}
};
This will generate the error you want in the const case and will compile in the non const case. Using auto allows a easier code writing for your code user.
IIUC, the elements which are either const or non-const are assigned at run-time, hence the type system (which is static) can not help you with that. You'd need to store some boolean flag with each element and perform a run-time check on assignment to see if it allowed or not.

How do I assign a data object with const members?

Hope this is not a duplicate. If so, please point me to it in a comment and I'll remove the question again.
I have a data object with data that's only valid in a bundle - i.e. there's no sense in changing the value of one member without invalidating the other members.
This data object describes some image information:
struct ImageInfo
{
ImageInfo(const double &ppix, ...)
: PpiX(ppix),
...
{ }
const double PpiX;
const double PpiY;
const int SizeX;
const int SizeY;
};
In my image object I have a non-const member of type ImageInfo:
class MyImageObject
{
...
private:
ImageInfo mMyInfo;
}
I want to be able to change mMyInfo at runtime, but only so that it will take a new ImageInfo(...) instance.
In the MyImageObject::Load() function, I'd like to read this data from the file info and then create an ImageInfo instance with the correct set of data:
double ppix = ImageFile.GetPpiX();
...
mMyInfo = ImageInfo(ppix, ...);
But I couldn't manage to write a valid assignment operator (copy constructor is possible of course). My solution left mMyInfo empty, because I didn't reference this:
ImageInfo operator=(const ImageInfo &other)
{
// no reference to *this
return ImageInfo(other);
}
Out of curiosity I'd like to know how the assignment operator for such a class would need to look like.
I'm using plain C++.
EDIT
Possible solutions (the goal is to keep the data transportable, but coherent):
Use private members together with Get...() functions -> simple, but I'd like to avoid the parentheses.
Store a pointer to ImageInfo: ImageInfo *mpMyInfo; (I'd like to avoid the heap.)
Use serialization and store the serialized ImageInfo, then create local instances from the serialized data.
I don't think you can have const member variables that aren't static. If you need const variables that change with the instance, you could do something like this:
struct ImageInfo
{
private:
double myPpiX;
double myPpiY;
int mySizeX;
int mySizeY
public:
ImageInfo(const double &ppix, ...)
: myPpiX(ppix),
PpiX(myPpiX),
...
{ }
ImageInfo( const ImageInfo &other)
: myPpiX( other.myPpiX),
PpiX(myPpiX)
...
{ }
const double &PpiX;
const double &PpiY;
const int &SizeX;
const int &SizeY;
// EDIT: explicit assignment operator was missing
ImageInfo& operator=(const ImageInfo &other)
{
myPpiX = other.myPpiX;
myPpiY = other.myPpiX;
mySizeX = other.mySizeX;
mySizeX = other.mySizeX;
return *this;
}
};
The values are stored in the private variables that can be set at construction, and their values accessed by const references. You're also not dependent on the references passed into the constructor living as long as the ImageInfo instance.
As they are data fields that can be modified, they are not const.
If you want to restrict post-construct access to them to const, you need to wrap them in accessors as follows:
struct ImageInfo
{
ImageInfo(const double &ppix, /*...*/)
: PpiX_(ppix),
/*...*/
{ }
double const& PpiX() const {return PpiX_; };
double const& PpiY() const {return PipY_; };
int const& SizeX() const {return SizeX_; };
int const& SizeY() const {return SizeY_; };
private:
double PpiX_;
double PpiY_;
int SizeX_;
int SizeY_;
};
That allows move/copy assignment and construction, while blocking non-const access outside of said construction.
Avoiding the () is tricky, but could be done with pseudo-references, something like this:
struct pseudo_const_reference_to_Ppix {
ImageInfo const* self;
operator double() const { return self->Ppix; }
void reseat( ImageInfo const* o ) { self = o; }
};
plus a whole pile of boilerplate to overload every const operator on the left and right such that the above pseudo_const_reference_* is just as valid as double.
Generic versions can be written (either taking a functor or a std::function if you are willing to suffer type erasure overhead).
Then you maintain these pseudo-const references on assignment and copy/move construction.
I think the () is the better option.
Note that the overhead of a pointer (or more) per pseudo-reference is basically unavoidable: member variables do not have access to the this from which they are invoked, even though the accesing site has it right there plain as day.
If something is const, you can't change it. Full stop.
So you must adjust the design somewhere, either not have those ImageInfo members const, not have ImageInfo as member, or best: not do the assignment.
Normally const members are set in constructor. You can make a load function that creates a MyImageObject object with all its content, so avoiding to have a half-done thing and load the sate in a second phase.
An alternative is to have the mMyInfo indirectly, say using unique_ptr, then you can replace it with another instance. I would not do that without a really good reason.
Immutable value objects are great. But the variable holding the value object (mMyInfo in MyImageObject) should be (non-constant) a pointer. In other languages (e.g. Java) this is automatically the case, but not in C++, where you need the * operator. Also, there is no need to override/implement the = operator for value objects. To change the image data within the image object, you assign a newly constructed ImageInfo object to the myImageInfo pointer. This way, none of the internal variables of the value object are changed.

C++: STL troubles with const class members

It is an open ended question.
Effective C++. Item 3. Use const whenever possible. Really?
I would like to make anything which doesn't change during the objects lifetime const. But const comes with it own troubles. If a class has any const member, the compiler generated assignment operator is disabled. Without an assignment operator a class won't work with STL. If you want to provide your own assignment operator, const_cast is required. That means more hustle and more room for error. How often you use const class members?
EDIT: As a rule, I strive for const correctness because I do a lot of multithreading. I rarely need to implemented copy control for my classes and never code delete (unless it is absolutely necessary). I feel that the current state of affairs with const contradicts my coding style. Const forces me to implement assignment operator even though I don't need one. Even without const_cast assignment is a hassle. You need to make sure that all const members compare equal and then manually copy all non-const member.
Code. Hope it will clarify what I mean. The class you see below won't work with STL. You need to implement an assignment for it, even though you don't need one.
class Multiply {
public:
Multiply(double coef) : coef_(coef) {}
double operator()(double x) const {
return coef_*x;
}
private:
const double coef_;
};
You said yourself that you make const "anything which doesn't change during the objects lifetime". Yet you complain about the implicitly declared assignment operator getting disabled. But implicitly declared assignment operator does change the contents of the member in question! It is perfectly logical (according to your own logic) that it is getting disabled. Either that, or you shouldn't be declaring that member const.
Also, providing you own assignment operator does not require a const_cast. Why? Are you trying to assign to the member you declared const inside your assignment operator? If so, why did you declare it const then?
In other words, provide a more meaningful description of the problems you are running into. The one you provided so far is self-contradictory in the most obvious manner.
As AndreyT pointed out, under these circumstances assignment (mostly) doesn't make a lot of sense. The problem is that vector (for one example) is kind of an exception to that rule.
Logically, you copy an object into the vector, and sometime later you get back another copy of the original object. From a purely logical viewpoint, there's no assignment involved. The problem is that vector requires that the object be assignable anyway (actually, all C++ containers do). It's basically making an implementation detail (that somewhere in its code, it might assign the objects instead of copying them) part of the interface.
There is no simple cure for this. Even defining your own assignment operator and using const_cast doesn't really fix the problem. It's perfectly safe to use const_cast when you get a const pointer or reference to an object that you know isn't actually defined to be const. In this case, however, the variable itself is defined to be const -- attempting to cast away the constness and assign to it gives undefined behavior. In reality, it'll almost always work anyway (as long as it's not static const with an initializer that's known at compile time), but there's no guarantee of it.
C++ 11 and newer add a few new twists to this situation. In particular, objects no longer need to be assignable to be stored in a vector (or other collections). It's sufficient that they be movable. That doesn't help in this particular case (it's no easier to move a const object than it is to assign it) but does make life substantially easier in some other cases (i.e., there are certainly types that are movable but not assignable/copyable).
In this case, you could use a move rather than a copy by adding a level of indirection. If your create an "outer" and an "inner" object, with the const member in the inner object, and the outer object just containing a pointer to the inner:
struct outer {
struct inner {
const double coeff;
};
inner *i;
};
...then when we create an instance of outer, we define an inner object to hold the const data. When we need to do an assignment, we do a typical move assignment: copy the pointer from the old object to the new one, and (probably) set the pointer in the old object to a nullptr, so when it's destroyed, it won't try to destroy the inner object.
If you wanted to badly enough, you could use (sort of) the same technique in older versions of C++. You'd still use the outer/inner classes, but each assignment would allocate a whole new inner object, or you'd use something like a shared_ptr to let the outer instances share access to a single inner object, and clean it up when the last outer object is destroyed.
It doesn't make any real difference, but at least for the assignment used in managing a vector, you'd only have two references to an inner while the vector was resizing itself (resizing is why a vector requires assignable to start with).
I very rarely use them - the hassle is too great. Of course I always strive for const correctness when it comes to member functions, parameters or return types.
Errors at compile time are painful, but errors at runtime are deadly. Constructions using const might be a hassle to code, but it might help you find bugs before you implement them. I use consts whenever possible.
I try my best to follow the advice of using const whenever possible, however I agree that when it comes to class members, const is a big hassle.
I have found that I am very careful with const-correctness when it comes to parameters, but not as much with class members. Indeed, when I make class members const and it results in an error (due to using STL containers), the first thing I do is remove the const.
I'm wondering about your case... Everything below is but supposition because you did not provide the example code describing your problem, so...
The cause
I guess you have something like:
struct MyValue
{
int i ;
const int k ;
} ;
IIRC, the default assignment operator will do a member-by-member assignment, which is akin to :
MyValue & operator = (const MyValue & rhs)
{
this->i = rhs.i ;
this->k = rhs.k ; // THIS WON'T WORK BECAUSE K IS CONST
return *this ;
} ;
Thus, this won't get generated.
So, your problem is that without this assignment operator, the STL containers won't accept your object.
As far I as see it:
The compiler is right to not generate this operator =
You should provide your own, because only you know exactly what you want
You solution
I'm afraid to understand what do you mean by const_cast.
My own solution to your problem would be to write the following user defined operator :
MyValue & operator = (const MyValue & rhs)
{
this->i = rhs.i ;
// DON'T COPY K. K IS CONST, SO IT SHOULD NO BE MODIFIED.
return *this ;
} ;
This way, if you'll have:
MyValue a = { 1, 2 }, b = {10, 20} ;
a = b ; // a is now { 10, 2 }
As far as I see it, it is coherent. But I guess, reading the const_cast solution, that you want to have something more like:
MyValue a = { 1, 2 }, b = {10, 20} ;
a = b ; // a is now { 10, 20 } : K WAS COPIED
Which means the following code for operator =:
MyValue & operator = (const MyValue & rhs)
{
this->i = rhs.i ;
const_cast<int &>(this->k) = rhs.k ;
return *this ;
} ;
But, then, you wrote in your question:
I would like to make anything which doesn't change during the objects lifetime const
With what I supposed is your own const_cast solution, k changed during the object lifetime, which means that you contradict yourself because you need a member variable that doesn't change during the object lifetime unless you want it to change!
The solution
Accept the fact your member variable will change during the lifetime of its owner object, and remove the const.
you can store shared_ptr to your const objects in STL containers if you'd like to retain const members.
#include <iostream>
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <vector>
class Fruit : boost::noncopyable
{
public:
Fruit(
const std::string& name
) :
_name( name )
{
}
void eat() const { std::cout << "eating " << _name << std::endl; }
private:
const std::string _name;
};
int
main()
{
typedef boost::shared_ptr<const Fruit> FruitPtr;
typedef std::vector<FruitPtr> FruitVector;
FruitVector fruits;
fruits.push_back( boost::make_shared<Fruit>("apple") );
fruits.push_back( boost::make_shared<Fruit>("banana") );
fruits.push_back( boost::make_shared<Fruit>("orange") );
fruits.push_back( boost::make_shared<Fruit>("pear") );
BOOST_FOREACH( const FruitPtr& fruit, fruits ) {
fruit->eat();
}
return 0;
}
though, as others have pointed out it's somewhat of a hassle and often easier in my opinion to remove the const qualified members if you desire the compiler generated copy constructor.
I only use const on reference or pointer class members. I use it to indicate that the target of the reference or pointer should not be changed. Using it on other kinds of class members is a big hassle as you found out.
The best places to use const is in function parameters, pointers and references of all kinds, constant integers and temporary convenience values.
An example of a temporary convenience variable would be:
char buf[256];
char * const buf_end = buf + sizeof(buf);
fill_buf(buf, buf_end);
const size_t len = strlen(buf);
That buf_end pointer should never point anywhere else so making it const is a good idea. The same idea with len. If the string inside buf never changes in the rest of the function then its len should not change either. If I could, I would even change buf to const after calling fill_buf, but C/C++ does not let you do that.
The point is that the poster wants const protection within his implementation but still wants the object assignable. The language does not support such semantics conveniently as constness of the member resides at the same logical level and is tightly coupled with assignability.
However, the pImpl idiom with a reference counted implementation or smart pointer will do exactly what the poster wants as assignability is then moved out of the implementation and up a level to the higher level object. The implementation object is only constructed/destructed whence assignment is never needed at the lower level.
I think your statement
If a class has const any member, the
compiler generated assignment operator
is disabled.
Might be incorrect. I have classes that have const method
bool is_error(void) const;
....
virtual std::string info(void) const;
....
that are also used with STLs. So perhaps your observation is compiler dependent or only applicable to the member variables?
I would only use const member iff the class itself is non-copyable. I have many classes that I declare with boost::noncopyable
class Foo : public boost::noncopyable {
const int x;
const int y;
}
However if you want to be very sneaky and cause yourself lots of potential
problems you can effect a copy construct without an assignment but you have to
be a bit careful.
#include <new>
#include <iostream>
struct Foo {
Foo(int x):x(x){}
const int x;
friend std::ostream & operator << (std::ostream & os, Foo const & f ){
os << f.x;
return os;
}
};
int main(int, char * a[]){
Foo foo(1);
Foo bar(2);
std::cout << foo << std::endl;
std::cout << bar<< std::endl;
new(&bar)Foo(foo);
std::cout << foo << std::endl;
std::cout << bar << std::endl;
}
outputs
1
2
1
1
foo has been copied to bar using the placement new operator.
It isn't too hard. You shouldn't have any trouble making your own assignment operator. The const bits don't need to be assigned (as they're const).
Update
There is some misunderstanding about what const means. It means that it will not change, ever.
If an assignment is supposed to change it, then it isn't const.
If you just want to prevent others changing it, make it private and don't provide an update method.
End Update
class CTheta
{
public:
CTheta(int nVal)
: m_nVal(nVal), m_pi(3.142)
{
}
double GetPi() const { return m_pi; }
int GetVal() const { return m_nVal; }
CTheta &operator =(const CTheta &x)
{
if (this != &x)
{
m_nVal = x.GetVal();
}
return *this;
}
private:
int m_nVal;
const double m_pi;
};
bool operator < (const CTheta &lhs, const CTheta &rhs)
{
return lhs.GetVal() < rhs.GetVal();
}
int main()
{
std::vector<CTheta> v;
const size_t nMax(12);
for (size_t i=0; i<nMax; i++)
{
v.push_back(CTheta(::rand()));
}
std::sort(v.begin(), v.end());
std::vector<CTheta>::const_iterator itr;
for (itr=v.begin(); itr!=v.end(); ++itr)
{
std::cout << itr->GetVal() << " " << itr->GetPi() << std::endl;
}
return 0;
}
Philosophically speaking, it looks as safety-performance tradeoff. Const used for safety. As I understand, containers use assignment to reuse memory, i.e. for sake of performance. They would may use explicit destruction and placement new instead (and logicaly it is more correct), but assignment has a chance to be more efficient. I suppose, it is logically redundant requirement "to be assignable" (copy constructable is enough), but stl containers want to be faster and simpler.
Of course, it is possible to implement assignment as explicit destruction+placement new to avoid const_cast hack
Rather than declaring the data-member const, you can make the public surface of the class const, apart from the implicitly defined parts that make it (semi)regular.
class Multiply {
public:
Multiply(double coef) : coef(coef) {}
double operator()(double x) const {
return coef*x;
}
private:
double coef;
};
You basically never want to put a const member variable in a class. (Ditto with using references as members of a class.)
Constness is really intended for your program's control flow -- to prevent mutating objects at the wrong times in your code. So don't declare const member variables in your class's definition, rather make it all or nothing when you declare instances of the class.