James
James

Reputation: 5425

Template Return Type with Default Value

So in writing a C++ template class, I have defined a method that returns an object of the templated type, as such:

template <typename T>
class Foo
{
public:
    T GetFoo()
    {
        T value;

        //Do some stuff that might or might not set the value of 'value'

        return value;
    }
 };

int main() {

    Foo<int> foo;

    foo.GetFoo();

    return 0;
}

This gives the following warning:

prog.cpp: In member function ‘T Foo<T>::GetFoo() [with T = int]’:
prog.cpp:15: warning: ‘value’ is used uninitialized in this function

I understand why this is happening - I am returning an uninitialized int as part of GetFoo. The thing is, if I were to use Foo<SomeClass>, the line T value; would initialize value using the default constructor of SomeClass.

I have managed to suppress this warning by doing the following:

    T GetFoo()
    {
        T value = T();

        //Do some stuff that might or might not set the value of 'value'

        return value;
    }

This seems to work for primitive types (such as int and float) and classes, at least so long as that class has a default constructor and copy constructor. My question is - is this the accepted way of solving this problem? Are there any side effects of this I should know about?

Upvotes: 7

Views: 14069

Answers (6)

Adam Romanek
Adam Romanek

Reputation: 1879

Boost addresses this problem in one of its utility template classes, namely boost::value_initialized and its relatives.

Upvotes: 0

xtofl
xtofl

Reputation: 41509

The line

T t;

Default constructs objects, yet declares uninitialized built-in types. There is no syntax to 'default construct' a local variable.

Therefore it's not trivial to write generic code that initializes a variable, whether built-in or class.

Wrapping the type into a member variable, however, may present a workaround that does not need copy construction (apart from the return statement):

template< typename T > struct Initializer {
   T t;
   Initializer()
   :t() // ====> default construction, works for classes _and_ built-in
   {}
};

Using this wrapper, you can build your code in a generic way:

template<typename T> T foo() {
  Initializer<T> i;
  // fill in i.t to your liking
  return i.t;
}

See a full-blown snippet at codepad.

Upvotes: 5

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361352

This seems to work for primitive types (such as int and float) and classes, at least so long as that class has a copy constructor

For classes, not only [public] copy-constructor, you also need public default constructor!

My question is - is this the accepted way of solving this problem?

Usually it's a good idea to provide public default constructor. STL containers use it all the time! If you don't have one, most (or maybe, all) STL containers would not work at many occasions.

See this example with private default constructor: http://ideone.com/EdPLu

Upvotes: 1

Mark B
Mark B

Reputation: 96241

Indeed that's the standard way to solve the problem. I don't believe there should be any side effects to worry about in this case.

Upvotes: 3

Nim
Nim

Reputation: 33655

Do you really want to return an un-initialized value from this function? Sounds like it could lead to a whole lot of crap later down the line.

Why don't you use an appropriate wrapper - if you have access to boost, consider boost::optional. This way, if you don't initialize it, it can be tested properly.

Upvotes: 1

ysdx
ysdx

Reputation: 9325

Sounds OK, if the class has no copy constructor, you will not be able to return it anyway.

Upvotes: 5

Related Questions