Consider the following code:
struct s
{
const int id;
s(int _id):
id(_id)
{}
};
// ...
vector<s> v; v.push_back(s(1));
I get a compiler error that 'const int id' cannot use default assignment operator.
Q1. Why does push_back() need an assignment operator?
A1. Because the current c++ standard says so.
Q2. What should I do?
A2. I will use smart pointers.
Q3. I came up with a "solution", which seems rather insane:
s& operator =(const s& m)
{
if(this == &m) return *this;
this->~s();
return *new(this) s(m);
}
Should I avoid this, and why (if so)? Is it safe to use placement new if the object is on the stack?
I don't want to give up the const specifier
Well, you have no choice.
s& operator =(const s& m) {
return *new(this) s(m);
}
Undefined behaviour.
There's a reason why pretty much nobody uses const
member variables, and it's because of this. There's nothing you can do about it. const
member variables simply cannot be used in types you want to be assignable. Those types are immutable, and that's it, and your implementation of vector
requires mutability.
Ok,
You should always think about a problem with simple steps.
std::vector<typename T>::push_back(args);
needs to reserve space in the vector data then assigns(or copy, or move) the value of the parameter to memory of the vector.data()[idx] at that position.
to understand why you cannot use your structure in the member function std::vector::push_back , try this:
std::vector<const int> v; // the compiler will hate you here,
// because this is considered ill formed.
The reason why is ill formed, is that the member functions of the class std::vector could call the assignment operator of its template argument, but in this case it's a constant type parameter "const int" which means it doesn't have an assignment operator ( it's none sense to assign to a const variable!!). the same behavior is observed with a class type that has a const data member. Because the compiler will delete the default assignment operator, expel
struct S
{
const int _id; // automatically the default assignment operator is
// delete i.e. S& operator-(const S&) = delete;
};
// ... that's why you cannot do this
std::vector<S> v;
v.Push_back(S(1234));
But if you want to keep the intent and express it in a well formed code this is how you should do it:
class s
{
int _id;
public:
explicit s(const int& id) :
_id(id)
{};
const int& get() const
{
return _id;
}; // no user can modify the member variable after it's initialization
};
// this is called data encapsulation, basic technique!
// ...
std::vector<S> v ;
v.push_back(S(1234)); // in place construction
If you want to break the rules and impose an assignable constant class type, then do what the guys suggested above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With