Reputation: 4214
Class Foo
has user-declared constructor and thus no implicitly-declared default constructor:
struct Foo {
Foo(...) {...}
};
It is then used in the std::vector
of std::pair
as follows:
std::vector<std::pair<std::string, Foo> >
Attempting to push back in the vector:
std::vector<std::pair<std::string, Foo> > v;
v.push_back(std::make_pair(std::string("some string"), Foo(...)));
The following error C2512:
'Foo' : no appropriate default constructor available
...\Microsoft Visual Studio 9.0\VC\include\utility(43):
while compiling class template member function 'std::pair<_Ty1,_Ty2>::pair(void)'
std::vector
documentation says it should accept copy-assignable and copy-constructible objects:
T must meet the requirements of CopyAssignable and CopyConstructible (until C++11).
The code compiles just fine with gcc and VS2008 (pre SP1).
What is causing the error? Is there a bug in VS2008 SP1? If yes, what are the work-arounds?
Upvotes: 2
Views: 233
Reputation: 4214
This is a bug in VS 2008 SP1. Simplest possible work-around is providing a default constructor when VS 2008 SP1 is detected.
After doing some research I found the thread on msdn forum describing similar situation. The thread contains an answer from Microsoft employee which provides clear explanation.
Here's the quote (shortened for brevity, emphasis mine):
Thanks for reporting this bug ... This was introduced in the Visual C++ 2008 Feature Pack, which was incorporated into SP1.
We used OR here (and in tuple's
_Move_operation_category
) intentionally. We wanted to considerpair<int, string>
to be fast-swappable (which it is). Unfortunately, we forgot that the Swaptimization requires a default constructor, and that pair/tuple allow user-defined types to sneak in. (With something likevector<T>
orshared_ptr<T>
, even ifT
doesn't have a default constructor, the vector orshared_ptr
does.) Clearly, this was my bad.There's a silver lining to this conformance bug: at least this error is letting you know that
vector<pair<foo, wstring> >
will be slower thanvector<wstring>
....
As workarounds, you can:
- Give foo a default constructor. This will fast-swap the wstring and general-swap the foo.
- Give foo a default constructor, and a swap() implementation that can be picked up through ADL. This will fast-swap both the wstring and the foo.
- Write your own pair. This will disable the "Swaptimization".
- Use
vector<pair<shared_ptr<foo>, wstring> >
. This will fast-swap theshared_ptr
andwstring
. Of course, now you're doing more dynamic memory allocations, so this is desirable only in certain circumstances.Note that when we get move semantics, this swap machinery will be eliminated, which is going to be so awesome.
After considering the work-arounds I went with #1: providing a default constructor if VS2008 SP1 is detected:
struct Foo {
Foo(...) {...}
#if _MSC_FULL_VER == 150030729 // Visual Studio 2008, SP1
Foo() {} //<- work-around for VS2008 SP1 bug
#endif
};
Upvotes: 1