用保证的非常量分配将非静态常量字段的常量强制转换为常量是否合法



我有以下代码,这些代码似乎总是有效的(msvc、gcc和clang(。

但我不确定这是否真的合法。在我的框架中,我的类可能有";两个构造函数"-一个进行简单成员初始化的普通C++构造函数和一个附加的成员函数";Ctor";其执行附加的初始化代码。例如,它用于允许调用虚拟函数。这些调用由一个通用的分配/构造函数处理;make_shared";。

代码:

#include <iostream>
class Foo
{
public:
constexpr Foo() : someConstField(){}
public:
inline void Ctor(int i)
{
//use Ctor as real constructor to allow for example calls to virtual functions
const_cast<int&>(this->someConstField) = i;
}
public:
const int someConstField;
};
int main()
{
//done by a generic allocation function
Foo f;
f.Ctor(12); //after this call someConstField is really const!
//
std::cout << f.someConstField;
}

修改const内存是未定义的行为。这里,默认构造函数已经在常量内存中分配了int

老实说,我不知道你为什么要这么做。如果你想用int初始化Foo,只需创建一个重载构造函数:

...
constexpr Foo(int i) : someConstField{i} {}

这是完全合法的,当创建const内存时,您正在初始化它,一切都很好。

如果出于某种原因,您希望在两个阶段初始化对象(如果没有工厂函数,不是是个好主意(,那么您不能也不应该使用const成员变量。毕竟,如果它在对象创建后可以更改,那么它将不再是常量。

根据经验,不应该有const成员变量,因为它会导致很多问题,例如移动对象。

当我说";常量存储器";这里,我指的是const语言规则限定的内存。因此,虽然内存本身在机器级可能是可写的,也可能不是可写的。但这并不重要,因为编译器会做它喜欢做的任何事情(通常它只是忽略对内存的任何写入,但这是UB,所以它可以做任何事情(。

否。

修改const值是未定义的行为。const_cast本身很好,问题出在改装上。

根据C++17标准中的7.1.6.1

除了任何声明为可变的类成员(7.1.1(都可以修改外,任何修改常量的尝试对象在其生存期内(3.8(会导致未定义的行为。

还有一个例子(与您的例子类似,只是不适用于类成员(:

const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object

如果分配函数分配原始内存,则可以使用placementnew在该内存位置构造对象。这样,您必须记住在释放分配之前调用对象的析构函数。

使用malloc:的小示例

class Foo
{
public:
constexpr Foo(int i) : someConstField(i){}
public:
const int someConstField;
};
int main()
{
void *raw_memory = std::malloc(sizeof(Foo));
Foo *foo = new (raw_memory) Foo{3}; // foo->someConstField == 3
// ...
foo->~Foo();
std::free(foo);
}
我建议您使用构造函数来避免const强制转换。您评论说,在调用Ctor之后,someConstField的值将保持常量。只要在构造函数中设置它,就不会有任何问题,代码也会变得更可读。
#include <iostream>
class Foo
{
public:
constexpr Foo(int i) : someConstField(Ctor(i)){}
int Ctor(); // to be defined in the implementation
const int someConstField;
};
int main()
{
Foo f(12);
std::cout << f.someConstField;
}

最新更新