代码之家  ›  专栏  ›  技术社区  ›  AMA

VS2008 SP1:将一对推送到vector中时,没有适当的默认构造函数可用

  •  2
  • AMA  · 技术社区  · 7 年前

    背景

    等级 Foo 有用户声明的构造函数,因此没有 implicitly-declared default constructor :

    struct Foo {
        Foo(...) {...}
    };
    

    然后用于 std::vector 属于 std::pair 如下:

    std::vector<std::pair<std::string, Foo> >
    

    用法

    尝试在矢量中向后推:

    std::vector<std::pair<std::string, Foo> > v;
    v.push_back(std::make_pair(std::string("some string"), Foo(...)));
    

    编译错误(VS2008 SP1)

    以下内容 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 表示它应该接受复制可分配对象和复制可构造对象:

      T 必须满足 可复制的 可拷贝构造 (直到C++ 11)。

    • 该代码与gcc和vs2008(sp1之前的版本)的编译非常好。

    问题

    导致错误的原因是什么?VS2008 SP1中是否存在错误?如果是,解决方法是什么?

    1 回复  |  直到 7 年前
        1
  •  1
  •   AMA    7 年前

    这是vs 2008 SP1中的一个错误。最简单的解决方法是在检测到VS 2008 SP1时提供默认的构造函数。

    解释

    在做了一些研究之后,我发现 thread on msdn forum 描述类似情况。该线程包含来自Microsoft员工的答案,该答案提供了清晰的解释。

    这是引言(简明扼要,强调我的):

    感谢您报告此错误… 这是在Visual C++ 2008功能包中介绍的,它是 并入SP1。

    我们用过还是在这儿(在图普尔 _Move_operation_category ) 故意。我们想考虑 pair<int, string> 成为 可快速交换(它是)。不幸的是,我们忘记了 swaptimization需要一个默认的构造函数,而该对/元组 允许用户定义的类型潜入。(有点像 vector<T> shared_ptr<T> ,即使 T 没有默认的构造函数, 矢量或 shared_ptr 是的。)显然,这是我的错。

    这个一致性错误有一线希望:至少这个错误 让你知道 vector<pair<foo, wstring> > 会变慢 比 vector<wstring> .

    作为 解决办法 ,您可以:

    1. 给foo一个默认的构造函数。这将快速交换wstring和常规交换foo。
    2. 给foo一个默认的构造函数,以及一个swap()实现,它可以通过adl获得。这将快速交换两个W字符串 还有比赛场地。
    3. 写你自己的一对。这将禁用“swaptimization”。
    4. 使用 vector<pair<shared_ptr<foo>, wstring> > . 这将快速交换 共享资源 wstring . 当然,现在你做的更具活力 内存分配,因此只有在某些情况下才需要这样做 情况。

    注意,当我们得到移动语义时,这个交换机制将 被淘汰了,这太棒了。

    周围的工作

    在考虑了解决方法之后,我使用1:如果检测到VS2008 SP1,则提供默认构造函数:

    struct Foo {
        Foo(...) {...}
    #if _MSC_FULL_VER == 150030729 // Visual Studio 2008, SP1
        Foo() {} //<- work-around for VS2008 SP1 bug
    #endif
    };