【问题标题】:boost variant busted in 1_54?boost 变种在 1_54 中被破坏?
【发布时间】:2013-11-01 00:03:11
【问题描述】:

我认为 Boost::variant 在 1_54 中被破坏了。 我正在尝试在 boost 变体中使用 std::unique_ptr 作为有界类型。

根据 1_54 文档,变体需要是可复制构造或可移动构造的。

http://www.boost.org/doc/libs/1_54_0/doc/html/variant/reference.html

所以我在我的代码中实现了移动构造函数并禁用了复制构造函数。

当我尝试将某些内容分配给变体对象时,它无法编译。 我尝试了各种不同的方法,包括使用 std::move 将数据分配给变体对象,但似乎没有任何效果。 在编译错误堆栈跟踪之后,我确定问题出在 variant.hpp 中,它试图备份 rhs 数据。我想知道你们的想法,如果我认为 boost 变体文档是错误的,请告诉我。

提前致谢。

我正在使用 vs2010 编译并使用 C++11。

这是我的测试代码:

#include <iostream>
#include <memory>
#include <utility>
#include <vector>
#include <string>


#pragma warning (push)
#pragma warning (disable: 4127 4244 4265 4503 4512 4640 6011)
#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include <boost/ref.hpp>
#include <boost/shared_ptr.hpp>
#pragma warning (pop)

#include <boost/foreach.hpp>
#include <boost/format.hpp>
using boost::format;
using boost::str;

using namespace std;

class UniqueTest
{
};

class Foo
{
  public:
  std::unique_ptr<UniqueTest> testUniquePtr;

     Foo()      { std::cout << "Foo::Foo\n";  }
     Foo (Foo&& moveData)
     {
     }               

     Foo& operator=(Foo&& moveData)
     {
     return *this;
     }

  private:
     Foo(Foo& tt);
     Foo& operator=(const Foo& tt);

};


int main()
{

  Foo x = Foo();
  boost::variant<std::wstring,Foo> m_result2;
     std::wstring  testString = L"asdf";

  m_result2 = testString; //Fails
  //m_result2 = std::move(testString); //Fails
  //m_result2 = std::move(x); //Fails

  boost::get<Foo>(m_result2).testUniquePtr.get ();
  return 0;
}

【问题讨论】:

  • 这不是“禁用复制构造函数”的意思:-S 而且您只是“实现”了最广泛意义上的移动构造函数。提示:删除 all 您的手动移动和复制构造函数;隐含提供的就好了。
  • 如果您没有用户定义的复制操作或析构函数,移动构造函数自动生成的。删除所有损坏的特殊成员函数并让编译器正确提供它们
  • @lukesignh,那么这是一个 MSVC 错误,它使用符合 C++11 的编译器进行编译
  • @DavidBrown,您需要制作用户定义的移动操作noexcept(因为默认的移动操作是隐式的)。 variant 不会使用move ops,如果这样做会抛出异常,避免数据丢失,以提供强大的异常安全保障
  • @lukesignh,我不知道它是否会对 VS2010 产生任何影响,但你可以尝试让你的移动构造函数 noexcept,看看这是否会让 variant 优先使用它您的私有(因此无法使用)复制构造函数。如果您不手动定义它应该是隐含的,但是 VS2010 早于 C++11 标准,我不知道它支持多少

标签: c++ boost c++11 variant


【解决方案1】:

我的代码是否可以为任何人编译?

不,它不会,variant 将尝试调用缺少的复制构造函数。 (Foo::Foo(Foo const&amp;) 甚至没有被声明):

boost/variant/variant.hpp|756 col 9| error: no matching function for call to ‘Foo::Foo(const Foo&)’

即使你声明了它,它也不起作用:

test.cpp|43 col 6| error: ‘Foo::Foo(const Foo&)’ is private

在cmets中已经提到但你需要

  • 使复制构造函数成为复制构造函数(为了良好的风格)

    Foo(Foo const& tt) = delete;
    Foo& operator=(const Foo& tt) = delete;
    
  • 使移动构造函数/赋值noexcept,否则(如std::vectorvariant 将拒绝移动东西,因为它不是异常安全的。

    Foo(Foo && moveData) noexcept { }    
    Foo& operator=(Foo && moveData) noexcept { return *this; }
    

这是一个在 GCC 和 Clang 上编译的简化示例:

#include <iostream>
#include <memory>
#include <string>
#include <boost/variant.hpp>

struct UniqueTest { };

struct Foo
{
public:
    std::unique_ptr<UniqueTest> testUniquePtr;

    Foo() { std::cout << "Foo::Foo\n"; }
    Foo(Foo && moveData) noexcept { }

    Foo& operator=(Foo && moveData) noexcept { return *this; }

    Foo(Foo const& tt) = delete;
    Foo& operator=(const Foo& tt) = delete;
};


int main()
{
    Foo x = Foo();

    boost::variant<std::wstring, Foo> m_result2;

    std::wstring  testString = L"asdf";
    m_result2 = testString; //Fails
    //m_result2 = std::move(testString); //Fails
    //m_result2 = std::move(x); //Fails
    boost::get<Foo>(m_result2).testUniquePtr.get();
}

【讨论】:

  • 我刚看到你的帖子。好吧,VS2010 不支持 nodelete 或 noexcept 关键字。除了自己定义之外,我还有其他选择吗?
猜你喜欢
  • 1970-01-01
  • 2012-07-24
  • 1970-01-01
  • 2020-02-15
  • 1970-01-01
  • 2021-10-04
  • 2020-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多