0

I was asking myself (and couldn't find an answer) if the modern C++ compilers could check into the body of the constructors to see if they could infer the initialization list, instead of letting the developer specifying it?

As an example, consider the following code:

MyClass::MyClass (Obj o)
{
    _o = o;
}

Can the compiler automatically translate it into:

MyClass::MyClass (Obj o) : _o(o)
{}

Thanks

Bastien Pasdeloup
  • 1,089
  • 12
  • 19
  • *Could* it? I suppose; but the meaning of the modified code might be different, so you wouldn't want it to. For example, if the assignment operator has side effects, or if it would change the order things happen in. Could a really, really smart compiler determine when this modification would produce no semantic changes and do it as an optimization in those cases only? I guess, but I doubt it would be worth it. – dlf Jun 30 '14 at 16:01

3 Answers3

1

No, because the semantics are different. The following direct-initializes the member _o from o:

MyClass::MyClass (Obj o) : _o(o)
{}

On the other hand, the following default-initializes _o and then assigns the value of o to it:

MyClass::MyClass (Obj o)
{
    _o = o;
}

In some cases there really might be no effective difference, such as if Obj is actually int. In cases where there is no effective difference, perhaps the compiler will generate the same code for both cases, but then again, maybe not. Depends how clever the optimizer is.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • The semantics is different if you take every operation taken in isolation. However, if you consider the state of your object after the initialization, then it is the same. – Bastien Pasdeloup Jun 30 '14 at 17:12
  • @BastienPasdeloup It might or might not be. Depends on the object. – Brian Bi Jun 30 '14 at 17:18
  • Sure, David Rodriguez pointed out some examples where the semantics differ. My point is that for most cases, a compiler should be able to detect and optimize it, so I was wondering if it is effectively done when it is 100% sure that the semantics remain equivalent – Bastien Pasdeloup Jun 30 '14 at 17:36
  • @BastienPasdeloup I can't see why the compiler wouldn't take an opportunity to optimize whenever possible. That said, I doubt that the compiler performs this particular optimization by introducing a *mem-initializer* into the AST. Much easier to deal with something like this in the IR, I would think. – Brian Bi Jun 30 '14 at 17:53
1

This is not possible as it completely changes the semantics of the program in the general case. Some of the examples:

// Order of evaluation:
struct Foo {
   int a, b;
   Foo() : b(a) { a = 1; }    // differs from Foo() : a(1), b(a) {}
};

// Legality of the operation:
struct X { explicit X(int x); };
struct Foo {
    X x;
    Foo() { x = 5; }              // Ill formed, while Foo() : x(5) is well formed
};

// Different effects even if allowed
struct X {
   X(int)            { std::cout << "int\n";        }
   X()               { std::cout << "default\n";    }
   X& operator=(int) { std::cout << "assignment\n"; }
};
struct Foo {
   X x;
   Foo() { x = 5; }          // prints: default\nassignment\n
   // Where Foo() : x(5) {}  // prints: int\n
};

At the language level both operations are completely different and cannot be transformed. That being said, the optimizer might be able to produce the exact same code for both if they are truly equivalent.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • You are completely right with your conter-examples. However, in the example I provided, the semantics remains the same. Thus, does any compiler (g++? clang?) optimizes it this way? – Bastien Pasdeloup Jun 30 '14 at 17:17
  • @Bastien: in that particular case, I would expect any optimizing compiler to generate the same code, which does not mean transforming at the language level. I already stated something on those lines in the last paragraph. – David Rodríguez - dribeas Jun 30 '14 at 18:45
0

They are checking (if member variables needs to be created with parameters).

For example, this :

struct A {
  A( int ) {}
};

struct B {
  B(){ a = A(3); }

  A a;
};

is going to fail with an error.

On the other hand, some types do not need parameters to be initialized. For example :

struct A
{
    A(){
        v = 3;
    }

    int v;
};

The standard doesn't require the compiler to issue a warning, but some compilers are capable of doing it (gcc has -Weffc++ flag).

Also, there are static code analysis tools to warn about such "errors".

Community
  • 1
  • 1
BЈовић
  • 62,405
  • 41
  • 173
  • 273