Non-owning holder with assignment semantics - c++

I have a class that should hold a reference to some data, without owning that data (i.e. the actual data is guaranteed not to go out of scope). In particular, the class cannot make a copy – the data is easily several gigabytes in size.
Now, the usual implementation (I assume) is to have a reference to the data:
struct holder_ref {
type const& value;
holder_ref(type const& value) : value(value) { }
};
(Please note that the constness has absolutely no bearing on the problem).
Now, I absolutely need this class to be assignable (i.e. have a working operator =). I thought this was a fairly common problem but I can’t remember how (if ever) I’ve solved it before.
The problem is that a reference cannot be assigned and there’s simply no way around this. The only solution I’ve come up with uses placement new in place of the assignment operator:
// x = other_x; gets replaced with:
x.~T();
new (&x) T(other_x);
Now, this works and is standard compliant. But it sure is ugly. No – inacceptable.
So I’m searching for alternatives. One idea is to use pointers, but I’m unsure whether my constructor is actually guaranteed to work (and passing a pointer is impossible due to the interface I have to adhere to):
struct holder_ptr {
type const* value;
// Is this legal?
holder_ptr(type const& value = 0) : value(&value) { }
};
But I’d rather use a reference, if at all possible. Only – how to implement the assignment operator?
struct holder_ref {
type const& value;
holder_ref(type const& value = 0) : value(value) { }
holder_ref& operator =(holder_ref const& other) {
// Now what?!
return *this;
}
};
As a test case, consider the following code:
int main() {
int const TEST1 = 23;
int const TEST2 = 13;
int const TEST3 = 42;
std::vector<holder_ptr> hptr(1);
std::vector<holder_ref> href(2);
// Variant 1. Pointer.
hptr[0] = holder_ptr(TEST1);
// Variant 2. Placement new.
href[0].~holder_ref();
new (&href[0]) holder_ref(TEST2);
// Variant 3. ???
href[1] = holder_ref(TEST3);
assert(*hptr[0].value == TEST1); // Works (?)
assert(href[0].value == TEST2); // Works
assert(href[1].value == TEST3); // BOOM!
}
(Also, just to make this clear – the type we’re talking about is non-POD and I need a standard compliant solution.)

I don't see anything wrong with using a holder_ptr. It can be implemented something like so:
struct bad_holder : std::exception { };
struct holder_ptr {
holder_ptr() : value(0) { }
holder_ptr(type const& value) : value(&value) { }
type const& get() {
if (value == 0) throw bad_holder();
return *value;
}
private:
type const* value;
};
So long as you always assign to the pointer from a reference, you know that you have a valid object (that, or you ended up with a "null reference" previously, in which case you have other, bigger problems since you'll already have invoked undefined behavior).
With this solution, the interface is implemented entirely in terms of references, but under the hood a pointer is used so that the type is assignable. The use of references in the interface ensures there are none of the concerns that come with using pointers (namely, you never have to worry whether the pointer is null).
Edit: I've updated the example to allow for the holder to be default constructible.

I'd use the pointer holder. But if you are dead set against that, how about hiding your placement new operator=:
holder_ref& operator =(holder_ref const& other) {
new (this) holder_ref(other);
return *this;
}

Is a TR1 weak_ptr standard compliant enough?

Related

Is std::optional<std::shared_ptr<MyClass>> good for avoiding null point deference?

I want to write safe C++ programs, therefore:
I wanted to avoid memory leaks, so I started using std::shared_ptr.
However, I still had some null pointer deferences some times. I've come up with the idea of using using MyClassSafe = std::optional<std::shared_ptr<MyClass>>.
Then I avoid both memory leaks and null pointer deference. Well, kind of. For example:
MyClassSafe myClassSafe = std::make_shared<MyClass>();
//Then everytime I want to use myClassSafe:
if (myClassSafe) {
//use it here
} else {
//do something in case no value
}
//However, this situation can be possible:
MyClassSafe notVerySafe = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClassSafe) {
//use it here, for example:
//this deferences a nullptr
myClassSafe.value()->someFunction();
} else {
//do something in case no value
}
so this is not much safer. It's better but I still can make mistakes.
I can imagine a safe_shared_ptr<T> class that instead of calling the object's functions on operator->, it could return std::optional<T&> (much like Rust) for which we can then safely call or deal with the std::nullopt case. Isn't there something already in C++? Or can it be implemented easily?
You haven't shown need for either pointers or optionals here.
MyClass myClassSafe;
myClassSafe.someFunction();
No possibility of null pointers or empty optionals in sight.
optional<T> allows you to handle the "no T available" case, which shared_ptr<T> already handles. Therefore optional<shared_ptr<T>> is redundant, just like optional<optional<T>> is.
There is a case to be made for shared_ptr<optional<T>> - if one owner creates the T object, the other owner can see the new object, so that isn't really redundant.
Your use of std::optional here is the cause of the problem. std::shared_ptr defines operator bool as a null pointer check, but because you have wrapped it in std::optional this never gets called
If instead you try:
MyClass myClass = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClass) {
// std::shared_ptr implements operator bool as a null pointer check
myClass->someFunction();
} else {
//do something in case no value
}
Isn't there something already in C++?
There is nothing in std to handle non null smart pointer.
As Caleth shows in his answer, you can use object directly and avoid (smart) pointer and std::optional.
Or can it be implemented easily?
Non null smart pointer (a "smart reference" :) ) should be non default constructible, and "non-movable" (I mean move should not invalidate the reference).
You could implement it with existing smart pointer, something like:
template <typename T>
class unique_ref
{
public:
// Avoid variadic constructor which might take precedence over regular copy/move constructor
// so I use tag std::in_place_t here.
template <typename ... Ts>
unique_ref(std::in_place_t, Ts&&... args) : std::make_unique<T>(std::forward<Ts>(args)...) {}
unique_ref(const unique_ref&) = delete;
unique_ref(unique_ref&&) = delete;
unique_ref& operator=(const unique_ref&) = delete;
unique_ref& operator=(unique_ref&&) = delete;
const T& operator*() const { return *ptr; }
T& operator*() { return *ptr; }
const T* operator ->() const { return ptr.get(); }
T* operator*() { return ptr.get(); }
private:
std::unique_ptr<T> ptr;
};
template <typename T, typename ... Ts>
unique_ref<T> make_unique_ref(Ts&&... args)
{
return {std::in_place, std::forward<Ts>(args)...};
}
unique version is not much useful, as non-copyable, non-movable. using directly T seems simpler.
shared version is copyable (its move should do identical to the copy)
A weak version might return an std::optional<shared_ref<T>>.

Validity of pointer returned by operator->

I'm implementing a two-dimensional array container (like boost::multi_array<T,2>, mostly for practice). In order to use double-index notation (a[i][j]), I introduced a proxy class row_view (and const_row_view but I'm not concerned about constness here) which keeps a pointer to the beginning and end of the row.
I would also like to be able to iterate over rows and over elements within a row separately:
matrix<double> m;
// fill m
for (row_view row : m) {
for (double& elem : row) {
// do something with elem
}
}
Now, the matrix<T>::iterator class (which is meant to iterate over rows) keeps a private row_view rv; internally to keep track of the row the iterator is pointing to. Naturally, iterator also implements dereferenciation functions:
for operator*(), one would usually want to return a reference. Instead, here the right thing to do seems to return a row_view by value (i.e. return a copy of the private row_view). This ensures that when the iterator is advanced, the row_view still points to the previous row. (In a way, row_view acts like a reference would).
for operator->(), I'm not so sure. I see two options:
Return a pointer to the private row_view of the iterator:
row_view* operator->() const { return &rv; }
Return a pointer to a new row_view (a copy of the private one). Because of storage lifetime, that would have to be allocated on the heap. In order to ensure clean-up, I'd wrap it in a unique_ptr:
std::unique_ptr<row_view> operator->() const {
return std::unique_ptr<row_view>(new row_view(rv));
}
Obviously, 2 is more correct. If the iterator is advanced after operator-> is called, the row_view that is pointed to in 1 will change. However, the only way I can think of where this would matter, is if the operator-> was called by its full name and the returned pointer was bound:
matrix<double>::iterator it = m.begin();
row_view* row_ptr = it.operator->();
// row_ptr points to view to first row
++it;
// in version 1: row_ptr points to second row (unintended)
// in version 2: row_ptr still points to first row (intended)
However, this is not how you'd typically use operator->. In such a use case, you'd probably call operator* and keep a reference to the first row. Usually, one would immediately use the pointer to call a member function of row_view or access a member, e.g. it->sum().
My question now is this: Given that the -> syntax suggests immediate use, is the validity of the pointer returned by operator-> considered to be limited to that situation, or would a safe implementation account for the above "abuse"?
Obviously, solution 2 is way more expensive, as it requires heap-allocation. This is of course very much undesirable, as dereferenciation is quite a common task and there is no real need for it: using operator* instead avoids these problems as it returns a stack-allocated copy of the row_view.
As you know, operator-> is applied recursively on the functions return type until a raw pointer is encountered. The only exception is when it's called by name like in your code sample.
You can use that to your advantage and return a custom proxy object. To avoid the scenario in your last code snippet, this object needs to satisfy several requirements:
Its type name should be private to the matrix<>::iterator, so outside code could not refer to it.
Its construction/copy/assignment should be private. matrix<>::iterator will have access to those by virtue of being a friend.
An implementation will look somewhat like this:
template <...>
class matrix<...>::iterator {
private:
class row_proxy {
row_view *rv_;
friend class iterator;
row_proxy(row_view *rv) : rv_(rv) {}
row_proxy(row_proxy const&) = default;
row_proxy& operator=(row_proxy const&) = default;
public:
row_view* operator->() { return rv_; }
};
public:
row_proxy operator->() {
row_proxy ret(/*some row view*/);
return ret;
}
};
The implementation of operator-> returns a named object to avoid any loopholes due to guaranteed copy elision in C++17. Code that use the operator inline (it->mem) will work as before. However, any attempt to call operator->() by name without discarding the return value, will not compile.
Live Example
struct data {
int a;
int b;
} stat;
class iterator {
private:
class proxy {
data *d_;
friend class iterator;
proxy(data *d) : d_(d) {}
proxy(proxy const&) = default;
proxy& operator=(proxy const&) = default;
public:
data* operator->() { return d_; }
};
public:
proxy operator->() {
proxy ret(&stat);
return ret;
}
};
int main()
{
iterator i;
i->a = 3;
// All the following will not compile
// iterator::proxy p = i.operator->();
// auto p = i.operator->();
// auto p{i.operator->()};
}
Upon further review of my suggested solution, I realized that it's not quite as fool-proof as I thought. One cannot create an object of the proxy class outside the scope of iterator, but one can still bind a reference to it:
auto &&r = i.operator->();
auto *d = r.operator->();
Thus allowing to apply operator->() again.
The immediate solution is to qualify the operator of the proxy object, and make it applicable only to rvalues. Like so for my live example:
data* operator->() && { return d_; }
This will cause the two lines above to emit an error again, while the proper use of the iterator still works. Unfortunately, this still doesn't protect the API from abuse, due to the availability of casting, mainly:
auto &&r = i.operator->();
auto *d = std::move(r).operator->();
Which is a death blow to the whole endeavor. There is no preventing this.
So in conclusion, there is no protection from a direction call to operator-> on the iterator object. At the most, we can only make the API really hard to use incorrectly, while the correct usage remains easy.
If creation of row_view copies is expansive, this may be good enough. But that is for you to consider.
Another point for consideration, which I haven't touched on in this answer, is that the proxy could be used to implement copy on write. But that class could be just as vulnerable as the proxy in my answer, unless great care is taken and fairly conservative design is used.

Safely return reference to member variable

In the library I am designing, I sometimes need read-access to large member variables of classes. Because of their size I don't want to make a getter that returns by copying the member. I don't want them to be modifiable from the outside, so I can't have them public or return references to them. So I thought I would use a "reader":
class TestClass
{
public:
explicit TestClass(double d): d_(d){}
const double& readD() const { return d_; }
private:
double d_;
};
(this is not really meant for doubles)
But here somebody could const_cast the reference and access the data directly. Even without assuming malicious intent, somebody could safe a reference to the data-member and keep it around after the original object has gone out of scope. I know const references can keep a temporary viable, but that doesn't remove the const_cast-problem.
So I came up with a workaround:
#include <iostream>
template<class T>
class SafeMemberReference
{
public:
using type = T;
SafeMemberReference(const T& t) :t(t) {}
explicit SafeMemberReference(T&& t) = delete;
operator const T& () && {return t; }
T get() && {return t; }
private:
const T& t;
};
class TestClass
{
public:
explicit TestClass(double d): d_(d){}
SafeMemberReference<double> readD() const { return d_; }
private:
double d_;
};
int main()
{
TestClass foo(1.2);
// temporary from read can be used as temporary in expressions
std::cout << foo.readD() << std::endl;
// temporary can be used to copy from
auto x = foo.readD().get();
// lvalue can not be used, so a possible dangling reference is no problem
auto ref = foo.readD();
//std::cout << ref << std::endl;
}
I have several questions to this:
Q1) How necessary is this from an efficiency POV? the largest objects I am returning are dense complex matrices with dimensions of maybe 1000x1000. These copies may happen frequently
Q2) Are my concerns about returning by const& valid?
Q3) Does this seem like a good solution? which drawbacks does it have?
Any solution that attempts to fight the language itself is not a good solution.
They should get a wrap on the knuckles if they used a const_cast in that way: the behaviour on trying to change an object via a const_cast on an object that was originally declared as const is undefined. Even if you manage to conjure up a solution to prevent that, a hostile programmer could still take the address of your object, offset that address (using unsigned char* pointer arithmetic) and modify a data member through that pointer!
So if I were you I wouldn't fight the language. Return a const reference if I were you, as per your original suggestion.
Code static analysis tools / compiler warnings / code reviews / human resource departments will help you keep other collaborative programmers on the straight and narrow.

Choosing constructor for a noncopyable object

Assume I have a non-copyable class with multiple constructors with like this
class Foo: boost::noncopyable
{
public:
Foo(std::string s) {...}; // construct one way
Foo(int i) {...}; // construct another way
}
Now, I want to construct an object, and choose which constructor to use at runtime:
I could do it with pointers like this:-
boost::shared_ptr<Foo> f;
if (condition)
f.reset(new Foo(myString));
else
f.reset(new Foo(myInteger));
// common code follows
f->doSomethingComplicated(...);
But that feels messy and slow. Is there an easy way to choose the constructor for the object without resorting to dynamic allocation?
Some more details : The Foo class above is simply to illustrate the problem.The actual class involved is Windows Gdiplus::Bitmap - http://msdn.microsoft.com/en-gb/library/windows/desktop/ms534420(v=vs.85).aspx
You can do it with C++11 on stack, without placement new and without copy/move constructor/assignment available. Observe:
auto factory = [&]() -> Foo
{
if (condition) {
return { myString };
} else {
return { myInteger };
}
};
Foo&& foo = factory();
foo.doSomethingComplicated();
The functor and the Foo instance will live happily on stack, no allocations made (except for copying string in Foo's constructor, probably). Foo will get its destructor called when it gets out of scope. Win.
When using uniform initialization to construct return value, no copy/move operation is involved. Note that returning myString (implicit conversion) or Foo(myString) would force compiler to check if object is copyable/moveable, even if such copy/move could be elided.
Edit: alternatively, this can be made even shorter, but bit more "magical":
Foo&& foo = [&]() -> Foo
{
if (condition) {
return { myString };
} else {
return { myInteger };
}
}();
Edit: Pre-C++11, Visual Studio hacky solution:
VC doesn't seem to check whether object is copyable when resorting on implicit conversion constructors to return value from a function. So this is valid, even though it's against the standard:
Foo make_foo(bool condition, const std::string&s, int i)
{
if ( condition) {
return s;
} else {
return i;
}
}
Then just use it like that:
Foo& f = make_foo(condition, myString, myInteger);
Note that this is yet another VC hack, as according to standard temporary can't be assigned to a reference to a mutable object, i.e. it would need to be changed const Foo&, which would be quite limiting here.
Not saying that you should handle it this way, but it is possible.
You have a flaw in your design. The 'Foo' is delegating the type elision to the user of the class. Have a look at boost::any (http://www.boost.org/doc/libs/1_55_0/doc/html/any.html)
I think the best option that meets your requirements (not dynamically allocated, not-copyable, pre-C++11) would be to use the placement new.
See here for a short example.
boost::optional might also be an acceptable option for you (it basically just does this for you internally, as well as keeping track of whether the object has been initialized). The in-place construction is a bit messy though for optional imo.
Keep it small and simple, I'd say. If this is a very local problem, why not just repeat the call?
if (condition)
{
Foo f(myString);
f.doSomethingComplicated();
}
else
{
Foo f(myInt);
f.doSomethingComplicated();
}
If that does not prove feasible, wrap a Foo pointer (or smart pointer) in a new class.
class FooWrapper // copyable
{
private:
boost::shared_ptr<Foo> m_foo;
public:
FooWrapper(std::string const &s) : m_foo(new Foo(s)) {}
FooWrapper(int i) : m_foo(new Foo(i)) {}
void doSomethingComplicated() { m_foo->doSomethingComplicated(); }
};
FooWrapper foo = condition ? FooWrapper(myString) : FooWrapper(myInt);
foo.doSomethingComplicated();
Using C++11 you can do:
Foo&& f = condition ? Foo{myInteger} : Foo{myString};
f.doSomethingComplicated();
By using an r-value reference you avoid the constness and still extend the lifetime of the temporary.
If you only need to construct a temporary object, I think you can bind it to a const reference using a ternary expression:
const Foo &f(condition ? Foo(myString) : Foo(myInteger));
f.doSomethingComplicated(...);

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.