在基本构造函数完成之前传递`this`:UB或只是危险? [英] Passing `this` before base constructors are done: UB or just dangerous?

查看:107
本文介绍了在基本构造函数完成之前传递`this`:UB或只是危险?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑这个最小的例子(我可以想到):

  struct Bar; 

struct Foo {
Bar * const b;
Foo(Bar * b):b(b){}
};

struct Bar {
Foo * const f;
Bar(Foo * f):f(f){}
};

struct Baz:Bar {
Baz():Bar(new Foo(this)){}
};

当通过 this code> Foo ,但尚未创建 Baz 的层次结构,但 Foo Bar 对他们收到的指针做任何有问题的操作。



现在的问题是,

问题2:如果<$ c $> $ c> Foo :: Foo(Bar *)是一个具有相同语义的 Foo :: Foo(Bar&)我必须通过 * this ,但是deref操作符在这种情况下不会做任何事情。

解决方案

这个问题直接在C ++标准3.8 / 5中回答:



在对象的生命周期开始之前,对象将占用已经被分配或者在对象的生存期结束之后并且在对象被占用的存储被重用或释放之前,可以使用引用对象将被或将被定位的存储位置的任何指针,而是仅使用在有限的方式。对于正在建造或销毁的对象,请参见12.7。否则,这样的指针指向分配的存储(3.7.4.2),并且使用指针,就像指针类型为void *一样,是明确定义的。这样的指针可以被取消引用,但是所得到的值仅可以以有限的方式使用,如下所述。该程序具有未定义的行为,如果:




  • 对象将是或是一个类类型与一个非平凡的析构函数,作为delete-expression的操作数,

  • 指针用于访问非静态数据成员或调用对象的非静态成员函数,或
  • 指针被隐式转换(4.10)为基类类型的指针,或

  • 指针用作static_cast(5.2.9)的操作数转换为void *或void *,随后为char *或unsigned char *),或

  • 指针用作dynamic_cast(5.2.7)的操作数。


此外,在12.7 / 3中:



要显式或隐式转换指针glvalue)将X类的对象引用到X的直接或间接基类B的指针(引用),X的构造以及直接或间接从B得到的所有直接或间接基础的构造应该具有并且这些类的销毁不会完成,否则转换会导致未定义的行为。


Consider this smallest example (I could think of):

struct Bar;

struct Foo {
  Bar* const b;
  Foo(Bar* b) : b(b) {}
};

struct Bar {
  Foo* const f;
  Bar(Foo* f) : f(f) {}
};

struct Baz : Bar {
  Baz() : Bar(new Foo(this)) {}
};

When passing this to the ctor of Foo, nothing in the hierarchy of Baz has been created, but neither Foo nor Bar do anything problematic with the pointers they receive.

Now the question is, is it simply dangerous to give away this in this fashion or is undefined behaviour?

Question 2: What if Foo::Foo(Bar*) was a Foo::Foo(Bar&) with the same semantics? I would have to pass *this, but the deref operator wouldn't do anything in this case.

解决方案

This question is answered directly in C++ standard 3.8/5:

Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a pointer refers to allocated storage (3.7.4.2), and using the pointer as if the pointer were of type void*, is well-defined. Such a pointer may be dereferenced but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if:

  • the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a delete-expression,
  • the pointer is used to access a non-static data member or call a non-static member function of the object, or
  • the pointer is implicitly converted (4.10) to a pointer to a base class type, or
  • the pointer is used as the operand of a static_cast (5.2.9) (except when the conversion is to void*, or to void* and subsequently to char*, or unsigned char*), or
  • the pointer is used as the operand of a dynamic_cast (5.2.7).

Additionally, in 12.7/3:

To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class X to a pointer (reference) to a direct or indirect base class B of X, the construction of X and the construction of all of its direct or indirect bases that directly or indirectly derive from B shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior.

这篇关于在基本构造函数完成之前传递`this`:UB或只是危险?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆