C++ std::对象向量和常量正确性
考虑以下几点:C++ std::对象向量和常量正确性,c++,vector,const-correctness,C++,Vector,Const Correctness,考虑以下几点: class A { public: const int c; // must not be modified! A(int _c) : c(_c) { // Nothing here } A(const A& copy) : c(copy.c) { // Nothing here } }; int main(int argc, char *argv
class A {
public:
const int c; // must not be modified!
A(int _c)
: c(_c)
{
// Nothing here
}
A(const A& copy)
: c(copy.c)
{
// Nothing here
}
};
int main(int argc, char *argv[])
{
A foo(1337);
vector<A> vec;
vec.push_back(foo); // <-- compile error!
return 0;
}
A类{
公众:
const int c;//不能修改!
A(整数c)
:c(_c)
{
//这里什么都没有
}
A(施工图A和副本)
:c(副本c)
{
//这里什么都没有
}
};
int main(int argc,char*argv[])
{
阿福(1337);
向量向量机;
vec.push_back(foo);//c
在operator=()
方法中,因此我不知道如何使用operator=()
(尽管std::vector
需要)(或复制赋值操作符),STL容器元素中的一个必须是复制可构造和可赋值的1(您的类A
不是)。您需要重载操作符=
一,
:§23.1
说存储在这些组件中的对象类型必须满足可复制的要求
类型(20.1.3),以及可分配类型的附加要求
编辑: 免责声明:我不确定以下代码是否100%安全。如果它调用UB或其他东西,请告诉我
A& operator=(const A& assign)
{
*const_cast<int*> (&c)= assign.c;
return *this;
}
A&运算符=(常量A&赋值)
{
*const_cast(&c)=assign.c;
归还*这个;
}
编辑2
我认为上面的代码片段调用了未定义的行为,因为试图摆脱
const
限定变量的常量调用UB
我认为您正在使用的向量函数的STL实现需要一个赋值操作符(请参阅标准中Prason的引用)但是,根据下面的引文,由于代码中的赋值运算符是隐式定义的(因为它不是显式定义的),因此由于您的类还具有常量非静态数据成员,因此您的程序的格式不正确
C++03
$12.8/12-“隐式声明
复制赋值运算符是隐式的
当其类的对象
为类型指定了其类的值
类型或类类型的值
从其类类型派生。一个程序
如果
复制赋值运算符是隐式的
定义有:
-常量类型的非静态数据成员,或
-非静态数据
引用类型的成员,或
-a
类类型的非静态数据成员
(或其阵列)具有
无法访问的复制分配运算符,
或
-具有不可访问属性的基类
复制赋值运算符
您还需要实现一个复制构造函数,如下所示:
class A {
public:
const int c; // must not be modified!
A(int _c)
...
A(const A& copy)
...
A& operator=(const A& rhs)
{
int * p_writable_c = const_cast<int *>(&c);
*p_writable_c = rhs.c;
return *this;
}
};
A类{
公众:
const int c;//不能修改!
A(整数c)
...
A(施工图A和副本)
...
A运算符=(常数A和rhs)
{
int*p_writable_c=const_cast(&c);
*p_可写_c=rhs.c;
归还*这个;
}
};
特殊的const_cast
模板采用指针类型,并将其转换回可写形式,用于此类情况
需要注意的是,使用
const\u cast
并不总是安全的,请参阅。无const\u cast的解决方法
A& operator=(const A& right)
{
if (this == &right) return *this;
this->~A();
new (this) A(right);
return *this;
}
我不知道为什么没有人这么说,但正确的答案是删除常量
,或者将A*
存储在向量中(使用适当的智能指针)
通过让“copy”调用UB或什么都不做(因此不是一个副本),你可以给你的类带来糟糕的语义,但是为什么要在UB和坏代码周围跳舞呢?通过使常量
,你得到了什么?(提示:什么都没有。)您的问题是概念性的:如果一个类有一个常量成员,那么该类就是常量。从根本上说,常量对象是无法分配的。
只需将其设置为非常量私有,并不可变地公开其值。对于用户来说,这是等效的,常量方面的。它允许隐式生成的函数正常工作。我最近遇到了同样的情况,我使用了std::set,因为其添加元素(insert)的机制不需要=运算符(使用<运算符),与vector的机制不同(向后推)
如果性能有问题,您可以尝试无序集或其他类似的方法。我只想指出,从C++11及更高版本开始,问题中的原始代码编译得很好!完全没有错误。但是,如果使用“placement new”(新位置),则会更好“在内部,因此更有效的方法是,将对象直接复制到向量末尾的内存中,而不是拥有额外的中间副本
(重点加上):
std::vector::emplace\u back
将新元素追加到容器的末尾。元素通过std::allocator\u traits::construct
构造,它通常使用placement new在容器提供的位置构造元素
下面是一个快速演示,演示了vec.push_back()
和vec.emplace_back()
现在都可以正常工作
在此处运行:
编译错误是什么?不要含糊其辞,做一个;写一个我想你有一个选择:要么你失去了常量,要么你失去了使用向量的能力。如果你开始解决这个问题,并允许操作符=
修改常量成员,你现在已经给了任何一段代码同样的方法。const int c;//不能被修改!你上面的评论是不是意味着“c”不应该被使用类A的对象或类A本身的成员修改?@anand:c应该只在构造函数中设置。在我的spe中
#include <cstdio>
#include <vector>
class A {
public:
const int c; // must not be modified!
A(int _c)
: c(_c)
{
// Nothing here
}
// Copy constructor
A(const A& copy)
: c(copy.c)
{
// Nothing here
}
};
int main(int argc, char *argv[])
{
A foo(1337);
A foo2(999);
std::vector<A> vec;
vec.push_back(foo); // works!
vec.emplace_back(foo2); // also works!
for (size_t i = 0; i < vec.size(); i++)
{
printf("vec[%lu].c = %i\n", i, vec[i].c);
}
return 0;
}
vec[0].c = 1337
vec[1].c = 999