请考虑以下代码:
struct s
{
const int id;
s(int _id):
id(_id)
{}
};
// ...
vector<s> v; v.push_back(s(1));
我收到编译错误,'const int id'不能使用默认赋值运算符。
<击> Q1。为什么push_back()需要赋值赋值运算符?
A1。因为当前的c ++标准是这样说的。
<击> Q2。我该怎么办?
<击> 撞击> A2。我将使用智能指针。
Q3。我提出了一个“解决方案”,这似乎相当疯狂:
s& operator =(const s& m)
{
if(this == &m) return *this;
this->~s();
return *new(this) s(m);
}
我应该避免这种情况,为什么(如果是这样)? 如果对象在堆栈中,使用placement new是否安全?
答案 0 :(得分:5)
C ++ 03要求存储在容器中的元素为CopyConstructible
和Assignable
(参见§23.1)。因此,实现可以决定在他们认为合适时使用复制构造和赋值。在C ++ 11中放松了这些约束。明确地,push_back
操作要求是类型为CopyInsertable
到向量中(参见§23.2.3序列容器)
此外,C ++ 11容器可以在插入操作中使用移动语义并继续操作。
答案 1 :(得分:3)
s& operator =(const s& m) { if(this == &m) return *this; this->~s(); return *new(this) s(m); }
我应该避免这种情况,为什么(如果是这样)?如果对象在堆栈上,使用placement new是否安全?
如果可以,你应该避免它,不是因为它形成不良,而是因为读者很难理解你的目标和对这段代码的信任。作为程序员,您应该致力于减少您编写的WTF /代码行数。
但,这是合法的。根据
void* operator new(std::size_t size, void* ptr) noexcept;
3备注:故意不执行任何其他操作。
调用placement new不会分配或释放内存,相当于手动调用s
的复制构造函数,如果s
有一个简单的析构函数,则根据[basic.life]/8
是合法的
答案 2 :(得分:2)
我不想放弃const说明符
嗯,你别无选择。
s& operator =(const s& m) {
return *new(this) s(m);
}
未定义的行为。
有一个原因,为什么几乎没有人使用const
成员变量,这是因为这个原因。你无能为力。 const
成员变量不能在您想要分配的类型中使用。这些类型是不可变的,就是这样,而vector
的实现需要可变性。
答案 3 :(得分:1)
Q2。我该怎么办?
存储指针,最好是智能。
vector<unique_ptr<s>> v;
v.emplace_back(new s(1));
答案 4 :(得分:1)
确定,
您应该始终通过简单的步骤来思考问题。
std::vector<typename T>::push_back(args);
需要在矢量数据中保留空格,然后将参数的值分配(或复制或移动)到该位置的 vector.data()[idx] 的内存中。
要理解为什么你不能在成员函数 std :: vector :: push_back 中使用你的结构,试试这个:
std::vector<const int> v; // the compiler will hate you here,
// because this is considered ill formed.
形成错误的原因是类 std :: vector 的成员函数可以调用其模板参数的赋值运算符,但在这种情况下它是一个常量类型参数&#34; const int &#34;这意味着它没有赋值操作符(分配给const变量是没意义的!!)。 对于具有 const数据成员的类类型,会发现相同的行为。因为编译器将删除默认赋值运算符,所以驱逐
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));
但是如果你想保留意图并在一个格式良好的代码中表达它,那么你应该这样做:
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
如果你想破坏规则并强加一个可分配的常量类类型,那么就按照上面提到的那样做。
答案 5 :(得分:0)
这不是一个真正的解决方案,而是一种解决方法:
#include <vector>
struct s
{
const int id;
s(int _id):
id(_id)
{}
};
int main(){
std::vector<s*> v;
v.push_back(new s(1));
return 0;
}
这将存储s
的指针而不是对象本身。至少它编译......;)
编辑:您可以使用智能c ++ 11指针增强此功能。见本杰明林德利的答案。
答案 6 :(得分:-2)
在赋值运算符中使用const_cast:
S& operator=(const S& rhs)
{
if(this==&rhs) return *this;
int *pid=const_cast<int*>(&this->id);
*pid=rhs.id;
return *this;
}