6

Considering

struct C { 
   C()            { printf("C::C()\n"          ); }
   C(int)         { printf("C::C(int)\n"       ); }
   C( const C& )  { printf("copy-constructed\n"); }
};

And a template function

template< typename T > void foo(){
    // default-construct a temporary variable of type T
    // this is what the question is about.
    T t1;       // will be uninitialized for e.g. int, float, ...
    T t2 = T(); // will call default constructor, then copy constructor... :(
    T t3();     // deception: this is a local function declaration :(
}

int main(){
    foo<int>();
    foo<C  >();
}

Looking at t1, it will not be initialized when T is e.g. int. On the other hand, t2 will be copy-constructed from a default constructed temporary.

The question: is it possible in C++ to default-construct a generic variable, other than with template-fu?

xtofl
  • 40,723
  • 12
  • 105
  • 192

4 Answers4

5

Here's a trick you can use, using a local class:

template <typename T> void foo() {
    struct THolder {
        T obj;
        THolder() : obj() { } // value-initialize obj
    };

    THolder t1; // t1.obj is value-initialized
}

I think I read about this trick from an answer to another Stack Overflow question, but I am unable to find that question at the moment.

Alternatively, you can use the boost::value_initialized<T> class template, which basically does the same thing, with greater flexibility and consistency and with workarounds for buggy compilers.

In C++0x, it's much easier: you can use an empty initializer list:

T obj{}; // obj is value-initialized

(To the best of my knowledge, only gcc 4.5+ supports C++0x initializer lists. Clang and Visual C++ don't yet support them.)

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • I think you could have read it from my answer to said question :) http://stackoverflow.com/questions/5300602/template-return-type-with-default-value/5300915#5300915 – xtofl Mar 14 '11 at 19:00
  • 1
    @xtofl: Ah, so you already know of this trick. To the best of my knowledge, it's the C++03 way to do it (in C++0x you can use an initializer list). [I hadn't seen that question this morning; this trick was mentioned sometime last year] – James McNellis Mar 14 '11 at 19:02
  • I was waiting for someone to mention C++0x. Could you give an example for that? – xtofl Mar 14 '11 at 19:07
  • @xtofl: I've added how this can be done with an empty C++0x initializer list. – James McNellis Mar 14 '11 at 19:58
  • 1
    @xtofl: In C++0x, that should be simply `X x{};` - However, it seems that at this time some compilers can (apparently mistakenly?!) invoke a constructor overload taking `initializer_list` if available (see http://ideone.com/Il93E and comment out the overload to compare). – UncleBens Mar 14 '11 at 19:59
  • Thanks. This kinda answers my question: no, there is no way in C++<0x, but C++0x foresees in the 'empty' initializer list. – xtofl Mar 14 '11 at 20:11
  • C++<0x looks like a big-headed, four-armed dude on a skateboard, or something. ;-) – James McNellis Mar 14 '11 at 20:17
  • @UncleBens, yep mistakenly. See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#990 – Johannes Schaub - litb Mar 14 '11 at 22:52
2

If you don’t care for the fact that the copy constructor must exist, and just want to prevent it being called:

Don’t worry: it won’t be. The copy constructor call will be elided in this situation. Always, and reliably – even when you compile with optimizations disabled (-O0).

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 2
    "Always, and reliably" -- on every C++ compiler ever made, and even when the copy constructor is inaccessible? – Ben Voigt Mar 14 '11 at 19:10
  • @Ben To the first part: on all that matter. To the second part: I’ve addressed that in the first sentence of my answer. – Konrad Rudolph Mar 14 '11 at 19:20
  • *"Always and reliably"* is a very tall claim! – Nawaz Mar 14 '11 at 19:20
  • @Nawaz This code is a fixed idiom and the standard explicitly mentions that compilers can optimize this. I’m reasonably sure that even not so recent compilers do the right thing. That said, I’m talking about the real world. Of course anyone could build a conforming compiler just to violate this one statement. But that’s not really relevant. – Konrad Rudolph Mar 14 '11 at 19:21
  • Although the compiler eliminates unnecessary copies, it would still require a copy constructor to be accessible. – Maxim Egorushkin Mar 14 '11 at 20:11
  • Even Visual C++ 6 does it, _even in debug_. Can't find source for this anymore, though. – Calvin1602 Mar 14 '11 at 20:16
  • @Konrad: A slight variation, and the copy-constructor didn't get elided (causing all manner of grief): http://stackoverflow.com/questions/5305391/winsock-accept-returning-wsaenotsock-code-10038 – Ben Voigt Mar 14 '11 at 22:54
  • @Ben Sorry but that’s a com-pur-letely different case. This question was specifically about default-constructing a templated value not about copy elision in return values. `T x = T()` is a common and known use-case because it’s often *necessary* to prevent the most vexing parse of `T x()` (and the likes). Every compiler vendor knows to expect that. – Konrad Rudolph Mar 15 '11 at 22:29
  • @Konrad: This question looks to me like it's about eliding the copy of the return value from the default constructor. True the other example is not a default constructor, but it's otherwise similar. – Ben Voigt Mar 15 '11 at 22:34
0

What is your real question? The default constructor is called for t1 instance.

florin
  • 13,986
  • 6
  • 46
  • 47
  • Yes, if `T` is a class type. If `T` is, e.g., `int`, then `t1` will be left uninitialized. – James McNellis Mar 14 '11 at 19:00
  • well... it isn't for `int`. I'll try to reformulate the question. – xtofl Mar 14 '11 at 19:01
  • @James: but what is the point of the exercise? Is it a trivia question? Is it trying to automatically initialize variables? – florin Mar 14 '11 at 19:02
  • It's trying to write generic code that works for classes as well as for built-in types, and does no overhead for either. – xtofl Mar 14 '11 at 19:06
0

T t2 = T(); // will call default constructor, then copy constructor... :(

Not on my compiler (VC2008). Output for me is...

C::C()
C::C()

Which is what I'd expect it to do. Am I missing something?

Martin Stone
  • 12,682
  • 2
  • 39
  • 53
  • 4
    That's because the call to the copy constructor can be elided. If the copy constructor was inaccessible or otherwise uncallable, then the `T t2 = T();` won't work. – James McNellis Mar 14 '11 at 19:03
  • Right, I get it now. Maybe the comment in the question needs to read "// Requires accessible copy constructor :(" – Martin Stone Mar 14 '11 at 19:08