在基ctor初始化程序中将其强制转换为“Derived*”合法吗
Is it legal to cast this to `Derived*` in the base ctor-initialiser?
给定以下CRTP示例:
template <typename T>
int foo(T* const)
{
return 0;
}
template <typename Derived>
struct Base
{
Base() : bar(foo(static_cast<Derived*>(this)) {};
int bar;
};
struct Derived1 : Base<Derived1> {};
此处this
到Derived*
的转换有效吗我似乎记得可能不是,但现在找不到具体的证据。
在这个阶段,this
的"自然"类型是Base* const
,在某些情况下,即使在初始化期间静态投射this
指针也是不好的,例如在基础结构完成之前(12.7/3)向上投射
@DeadMG表示:
在标准w.r.t.中有一个显式异常,在初始值设定项列表中获取该值。它用于将指向自己的指针传递给子对象。
12.6.2/12确实说明:
[注意:因为mem初始值设定项是在构造函数的作用域中计算的,所以this指针可以在mem初始设定项的表达式列表中用来引用正在初始化的对象。--end Note]
尽管这不足以说明到CCD_ 6的转换是有效的。
我的直觉是,在对象初始化的这个阶段,this
不会指向Derived
的实例,因此,即使有一个类型为Derived*
的指针,严格来说,也是UB。这是因为它既不是有效指针,也不是空指针。
(这可能会对这样的方法产生实际影响,尽管在这个答案和我上面的例子中,整个事情可以通过简单地编写static_cast<Derived*>(0)
来实现。)
我认为是UB。
正如Mike所说:
此时,已经为整个对象分配了存储,但只初始化了基本子对象。因此,您只能以C++11中描述的"有限的方式"使用对象的其余部分。
我的解释是,这不是那种方式。
更正式的:
[C++11: 3.8/1]:
对象的生存期是该对象的运行时属性如果一个对象是类或聚合类型,并且它或它的一个成员是由非平凡默认构造函数的构造函数初始化的,则称它具有非平凡初始化[注意:通过琐碎的复制/移动构造函数进行的初始化是非琐碎的初始化--结束语]类型为T
的对象的生存期从以下时间开始:
- 获得具有用于类型
T
的适当对准和大小的存储器,并且- 如果对象进行了非平凡的初始化,那么它的初始化就完成了
和:
[C++11: 3.8/5]:
在对象的生存期开始之前,但在分配对象将占用的存储之后,或者在对象的生命期结束之后,在对象所占用的存储被重用或释放之前,可以使用任何指向对象将要或曾经所在的存储位置的指针,但只能以有限的方式使用对于正在建造或毁坏的物体,请参见12.7。否则这样的指针指的是所分配的存储(3.7.4.2),并且使用该指针就像该指针是void*
类型一样,是明确定义的。这样的指针可以被取消引用,但产生的左值只能以有限的方式使用,如下所述程序有未定义的行为,如果:
- 对象将是或曾经是具有非平凡析构函数的类类型,并且指针用作删除表达式的操作数
- 指针用于访问非静态数据成员或调用对象的非静态成员函数,或者
- 指针被隐式转换(4.10)为指向基类类型的指针,或者
- 指针用作
static_cast
的操作数(5.2.9)(转换为void*
或void*
并随后转换为char*
或unsigned char*
时除外),或- 指针用作
dynamic_cast
[..]的操作数
- 防止主数据类型C++的隐式转换
- 将sharet_ptr<Derived>转换为shared_ptr<Base>
- 如何将unique_ptr<derived>*转换为<base>unique_ptr*?
- 为什么在此示例中从unique_ptr自动向上转换<derived>到unique_ptr<base>失败?
- 候选函数不可行:没有从 std::vector<derived> 到 std::vector <base>的已知转换
- 派生到矩阵库转换背后的故事<Derived>
- 如何将标准::make_unique<derived>() 转换为标准::unique_ptr<base>
- 将 std::shared_ptr<Derived> 转换为 const <Base>shared_ptr&
- 特征::<Derived> <Derived> 当列数固定时,无法将块转换为 Ref
- 从 Foo<Derived> 到 Foo <Base>的转换
- 为什么不允许从 VirtualBase::* 转换为 Derived::*?
- 无法将"derived"强制转换为其私有基类"base"
- 是否存在将实际Base下转换为Derived的情况
- 无法将"member pointer to derived class"转换为"member pointer to base class"
- 如果 Derived 没有向 Base 添加新成员(并且是 POD),则可以安全地完成哪种指针强制转换和取消引用
- <derived> 从函数返回时如何从shared_ptr转换为shared_ptr<base>?
- C++将 std::vector<Derived>* 转换为 std::vector<Base> ...?
- 将 std:vector<reference_wrapper<Base>> 转换为 std:vector<reference_wrapper<Derived>
- 在基ctor初始化程序中将其强制转换为“Derived*”合法吗
- 从Base*容器向下强制转换为Derived*容器,无需显式转换