C++ const对象的构造
C++11§12.1/14: 在const对象的构造过程中,如果对象或其任何子对象的值是通过 不是直接或间接从构造器的 指针,则获取对象或子对象的值 未指明。[示例:C++ const对象的构造,c++,constructor,constants,C++,Constructor,Constants,C++11§12.1/14: 在const对象的构造过程中,如果对象或其任何子对象的值是通过 不是直接或间接从构造器的 指针,则获取对象或子对象的值 未指明。[示例: structc; 无效无选择(C*); 结构C{ INTC; C():C(0){no_opt(this);} }; 常数C-cobj; 无效无选项(C*cptr){ //未指定cobj.c的值 int i=cobj.c*100; cptr->c=1; //未指定cobj.c的值 cout真正的const对象可能被编译器视为合法常量
structc;
无效无选择(C*);
结构C{
INTC;
C():C(0){no_opt(this);}
};
常数C-cobj;
无效无选项(C*cptr){
//未指定cobj.c的值
int i=cobj.c*100;
cptr->c=1;
//未指定cobj.c的值
cout真正的const
对象可能被编译器视为合法常量。它可以假定它们的值永远不会改变,甚至将它们存储在const
内存中,例如ROM或闪存。因此,只要对象实际上不是常量,您就需要使用this
提供的非常量访问路径。这种情况仅在对象构造和破坏期间存在
顺便说一句,我认为不需要对析构函数有相应的要求,因为对象生命周期已经结束,cobj.c
的析构函数一开始就不可访问
正如Matthieu所提到的,在构建或销毁过程中,除了通过这个访问对象之外,访问对象是一种强烈的“代码气味”。回顾C++11§3.8[基本生活]^1和6中,构造函数中的cobj.c
似乎是UB,原因与它在析构函数中的原因相同,而不管对象是const
或§12.1/14,因为它的生命周期直到初始化完成才开始(构造函数返回)
它可能会起作用,但它会为优秀的C++程序员敲响警钟,而这本书是非法的。< /P> < P>规则的原因是允许编译器作出。
基于对象常量的优化。例如,
根据优化的不同,编译器可能会替换第二个
cobj.c*100
inno_opt
withi
。更可能的情况是,在这种情况下
在这种情况下,优化器将抑制i
及其初始化
完全正确,因此代码看起来会工作。但这可能不是
如果您在更改cptr->c
之前还输出了i
,则视情况而定
编译器优化的力度。但允许编译器
假设*cptr
不是cobj
的别名,因为cobj
是
const对象,当您通过*cptr
进行修改时,它不能指向
没有未定义行为的常量对象
当然,如果对象不是const,那么问题就不会发生
编译器必须始终考虑到
*cptr
和cobj
我要注意的是,在上面的例子中,cobj.c
在cobj
完全构造之前就被访问了。在我看来,即使对于非常量对象,这个操作也是可疑的。@MatthieuM.Why?在我看来是有效的(即使您向struct c添加了基类)@VJovic:只要构造函数还没有运行,对象就还没有激活——请看Sutter的介绍。如果对象还没有激活,访问它是可疑的。我并不是说它一定没有定义或未指定,只是说它“闻起来很难闻”。我不理解它的措辞。cptr
是从这个中获得的,但引用中说“未获得”(如何获得)?此外,此引号意味着构造函数主体不得修改任何成员,否则const对象的行为将不确定?@visitor:问题是在构造函数返回之前使用cobj
。读取访问是有问题的。C():C(0){C=1;}
-那么你的意思是这也是无效的?这似乎离题了:它没有解决cobj.c
在c
的构造函数运行期间(即使在初始化的列表运行之后)有一个未指定的值这一事实。它也没有解决行为不同的原因(在这方面)在常量对象和非常量对象之间。@MatthieuM。我想我已经讨论了这两个问题。问题是编译器可以识别cobj.c
访问路径具有无法更改的值。无论哪个函数访问它,没有常量值的const
对象都是禁止的。啊,我终于得到了什么你刚才说的是“非常量访问路径”,很抱歉太密集了。
struct C;
void no_opt(C*);
struct C {
int c;
C() : c(0) { no_opt(this); }
};
const C cobj;
void no_opt(C* cptr) {
// value of cobj.c is unspecified
int i = cobj.c * 100;
cptr->c = 1;
// value of cobj.c is unspecified
cout << cobj.c * 100 << '\n';
}