Using this pointer in the initializer list

struct T { int a; }; struct C { T& r; C(T& v) : r(v) {} }; struct E : T { T& r; E(T const& v) : r(*this), T(v) {} // ok }; struct F : C, T // base order doesn't matter here { //F(T const& v) : C(*this), T(v) {} // error : C::r is not initialized properly F(T const& v) : C(*static_cast<T*>(this)), T(v) {} // ok //F(T const& v) : C(static_cast<T&>(*this)), T(v) {} // ok }; int main() { T v; F f(v); fra = 1; } 

Although using this pointer in the initializer list may be a problem, I never expected this to happen with the POD and could just be fixed with an explicit throw; Is this a compiler error or std related issue?

+6
source share
4 answers

The code is ambiguous.

To build a base C F context is direct initialization, therefore 13.3.1.3 is applied:

13.3.1.3 Initialization by the constructor [over.match.ctor]

For direct initialization, the candidate function is all the constructors of the initialized object class.

An implicitly declared copy instance is included at 12.8: 8.

Candidates for the C constructor are C(T &) and (the default copy constructor) C(const C &) , according to the parameter list (F) . In both cases, we have a linking (13.3.3.1.4), followed by a conversion with the derived base (13.3.3.1) with additional correction of cv-qualification in the latter case, giving a common conversion rank in both cases.

Since C and T are the base classes of F , but they are different types, and none of them is the base class of the other, none of the provisions in 13.3.3.2.3 and 13.3.3.2-00-00 applied and conversion sequences are indistinguishable.

Indeed, gcc-4.5.1 rejects the code with:

 prog.cpp: In constructor 'F::F(const T&)': prog.cpp:20:34: error: call of overloaded 'C(F&)' is ambiguous prog.cpp:9:5: note: candidates are: C::C(T&) prog.cpp:7:1: note: C::C(const C&) 
+3
source

When trying to initialize a C base from F using *this , both the copy constructor created by the compiler for C and the constructor that you define using T& correspond to the *this ( F ) type is derived directly from C and T Your cast eliminates this ambiguity.

I am surprised that the copy constructor is better than the one that accepts T& , since I would think that both of them would be equally preferable. If a copy constructor is selected, the base will be initialized by itself, which will lead to undefined behavior, since the reference element will be initialized from an uninitialized link (itself).

+3
source
  struct C
 {
     T & r;
     C (T & v): r (v) {}
 };

 struct E: T
 {
     T & r;
     E (T const & v): r (* this), T (v) {} // ok
 };

You need to initialize any link during the declaration, but here you just declared it. This is not allowed in C ++.

0
source

1) never use this in the initialization list http://msdn.microsoft.com/en-us/library/3c594ae3(v=vs.80).aspx This pointer is valid only inside non-static member functions. It cannot be used in the initialization list for the base class.

Base class constructors and class member constructors are called before this constructor. In essence, you passed a pointer to an unconstructed object to another constructor. If these other constructors access any members or call member functions to do this, the result will be undefined. You should not use this pointer until the completion of the entire construction.

coming soon: Cr initialized by bad poiter

0
source

Source: https://habr.com/ru/post/922289/


All Articles