如何解决在gcc 4.7和4.9之间std::vector的不同行为?

3

我有一些可以在gcc 4.9中编译的东西,但在gcc 4.7中失败了。

这是一个具有移动构造函数的类,但我将其复制构造函数设置为私有:

class Option
{
public:
    Option(const std::string& name_long,
           char               name_short,
           const std::string& group,
           bool*              value_store,
           int32_t            flags,
           const std::string& option_desc);
    // and several similar constructors

    Option(Option&& other);

private:
    Option(const Option& other);
};

问题出现在向量的emplace_back()函数中调用时:
// options is a std::vector<Option>
options.emplace_back("help", 'h', OPTION_GROUP_MISC,
                     &opt_show_help, htio2::Option::FLAG_NONE,
                     "Show help and exit.");

这段代码可以通过gcc 4.9成功编译且运行良好,但是在gcc 4.7下会出现一个两屏幕长的错误提示,称其复制构造函数为私有:

In file included from /public/yx/works/writing_tcrklass2/src/TCRklass2-1.90.0-Source/src/tcrk2/App.h:4:0,
                 from /public/yx/works/writing_tcrklass2/src/TCRklass2-1.90.0-Source/src/tcrk2/App.cpp:1:
......
/public/yx/works/writing_tcrklass2/src/TCRklass2-1.90.0-Source/src/tcrk2/App.cpp:58:47:   required from here
/usr/local/include/htio2/OptionParser.h:188:5: error: ‘htio2::Option::Option(const htio2::Option&)’ is private
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/move.h:57:0,
......
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/type_traits:762:43: error: within this context

作为我的一些用户使用的是非常老旧的系统,很可能使用旧版编译器,我真的想知道是否有任何方法可以解决这个问题。
3个回答

2

如果您从未使用过复制构造函数,而不是将其设置为私有,您可以将其删除:

Option(const Option&) = delete;

这可能有助于编译器选择正确的可用构造函数。

否则,您可以尝试手动构建临时对象并将其移回:

options.push_back(Option("help", 'h', OPTION_GROUP_MISC,
                         &opt_show_help, htio2::Option::FLAG_NONE,
                         "Show help and exit."));

2
你可以删除它,[...],这可能有助于编译器选择正确的可用构造函数。已删除的函数会参与重载决策,就好像它们存在一样。如果被选中,将会引发错误。 - Piotr Skotnicki
@PiotrS。当然。你认为如果使用“private”失败了,那么使用“delete”也不可能成功吗?我们正在讨论旧版gcc中的一个错误:似乎很难预测其行为,我会尝试一次。 - DarioP
如果解决方案旨在具有可移植性和符合性,我不会“试一试”。 - Piotr Skotnicki
1
@PiotrS。这个页面上的所有内容都是可移植的,并符合标准C++11,不是吗?唯一不符合标准的是编译器错误,如果你想或需要与它们共存,你需要找到一些它们喜欢的东西... - DarioP
@PiotrS。问题在于GCC 4.7没有将访问检查作为模板参数替换的一部分来实现,因此私有复制构造函数在与SFINAE一起使用时效果不佳,而删除的函数可以与SFINAE一起使用。因此,在GCC 4.7中,私有函数和删除函数并不等效,并且针对具有私有复制构造函数的类型,is_copy_constructible特性会产生错误。 - Jonathan Wakely
显示剩余2条评论

2

g++ 4.7需要一个noexcept移动构造函数:

Option(Option&& other) noexcept {};

它不起作用。编译器仍然会去查找复制构造函数。 - jiandingzhe
@jiandingzhe,在我的简单测试中,使用4.7.0、4.7.1、4.7.2或4.7.3都可以正常工作,所以你在实际代码中可能做了一些不同的事情。无论如何,即使你通过删除复制构造函数来解决问题,定义移动构造函数使其不能抛出异常并添加noexcept也是一个好主意。 - Jonathan Wakely

-2

如果你不想复制,可以使用 shared_ptr。

class Option;
typedef boost::shared_ptr<Option> OptionPtr;

OptionPtr o = boost::make_shared<Option>("help", 'h', OPTION_GROUP_MISC,
                         &opt_show_help, htio2::Option::FLAG_NONE,
                         "Show help and exit.");

std::vector<OptionsPtr> options;
options.push_back(o);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接