views:

93

answers:

2

The following snippet gives the warning:

[C++ Warning] foo.cpp(70): W8030 Temporary used for parameter '_Val' in call to 'std::vector<Base *,std::allocator<Base *> >::push_back(Base * const &)'

.. on the indicated line.

class Base
{
};

class Derived: public Base
{
public:
 Derived()   // << warning disappears if constructor is removed!
 {
 };
};

std::vector<Base*> list1;
list1.push_back(new Base);
list1.push_back(new Derived);  // << Warning on this line!

Compiler is Codegear C++Builder 2007.

Oddly, if the constructor for Derived is deleted, the warning goes away... Is it me or the compiler?

EDIT: The only way I've found to remove the warning is to something similar to this:

Derived * d;
list1.push_back(d = new Derived);  // << No warning now...
+1  A: 

Simple try:

list1.push_back(new Derived());

I am afraid there is something about POD (with trivial constructors) vs non-POD going on here.

EDIT:

Given that the code compiles fine with gcc.3.4.2 (--pedantic) I would say it's a compiler quirk. I am leaning toward MarkB explanation, ie the compiler creating a temporary even though I don't understand why it would be required and then complaining when assigning it to the const&... but I'm still perplex.

Matthieu M.
nice try, but no difference!
Roddy
It's annoying that I don't have the compiler handy to experiment with it :/ It's really bizarre that the same warning is not generated for `Base`: or perhaps it's because `Base` does not have a user defined constructor ?
Matthieu M.
@Matthieu M. - Base did have a user-defined constructor, but I trimmed it out as it made no difference to the problem. ie, using 'new Base' never gave a warning...
Roddy
It does appear to be a compiler bug.There's an open QC report on this issue, "Incorrect warning W8030." with almost identical code snippet.http://qc.embarcadero.com/wc/qcmain.aspx?d=59272
Roddy
+1  A: 

Since list1 is a vector of Base*, the push_back function in the list is going to expect a parameter of type Base* const&, while your new is providing Derived*. In order to pass by reference (as needed in push_back) the compiler needs an actual object of the reference type, in this case Base*. There is an available implicit conversion from Derived* to Base* that the compiler uses to create a temporary object of type Base* to pass into push_back, and the compiler is warning you that it's creating this temporary.

The reason it works when you assign it to a variable is that there's no longer an implicit temporary needed: It can implicitly convert the named variable to Base* implicitly and pass that reference in.

I think you can silence this warning by telling push_back to treat the pointer as a Base*:

list1.push_back(static_cast<Base*>(new Derived));

Mark B
Hmm. The cast doesn't change things, but I see what you're saying. I'm still not sure of the difference between the two implicit conversions, though.
Roddy
OK, so why does the presence of the Derived() constructor matter...?
Roddy
Matthieu M.