不可复制的对象和值初始化:g ++ vs msvc

R S*_*hko 4 c++ gcc visual-c++ value-initialization

我看到g ++和msvc在初始化不可复制对象的值之间有一些不同的行为.考虑一个不可复制的类:

class noncopyable_base
{
public:
    noncopyable_base() {}

private:
    noncopyable_base(const noncopyable_base &);
    noncopyable_base &operator=(const noncopyable_base &);
};

class noncopyable : private noncopyable_base
{
public:
    noncopyable() : x_(0) {}
    noncopyable(int x) : x_(x) {}

private:
    int x_;
};
Run Code Online (Sandbox Code Playgroud)

和一个使用值初始化的模板,以便即使类型为POD,该值也将获得已知值:

template <class T>
void doit()
{
    T t = T();
    ...
}
Run Code Online (Sandbox Code Playgroud)

并尝试将它们一起使用:

doit<noncopyable>();
Run Code Online (Sandbox Code Playgroud)

从VC++ 9.0开始,这在msvc上运行正常,但在每个版本的g ++上都失败了我用它(包括版本4.5.0)进行了测试,因为复制构造函数是私有的.

两个问题:

  1. 哪种行为符合标准?
  2. 任何关于如何在gcc中解决这个问题的建议(并且要明确,将其更改T t;为不可接受的解决方案,因为这会打破POD类型).

PS我看到与boost :: noncopyable相同的问题.

Mic*_*urr 8

你在MSVC中看到的行为是一个扩展,虽然它在下一页以迂回的方式记录(强调我的)http://msdn.microsoft.com/en-us/library/0yw5843c.aspx:

等号初始化语法与函数式语法不同,即使生成的代码在大多数情况下是相同的.不同之处在于,当使用等号语法时,编译器必须表现得好像发生了以下事件序列:

  • 创建与正在初始化的对象类型相同的临时对象.
  • 将临时对象复制到对象.

在编译器执行这些步骤之前,必须可以访问构造函数.即使编译器在大多数情况下可以消除临时创建和复制步骤,但是无法访问的复制构造函数会导致等号初始化失败(在/ Za,/ Ze(禁用语言扩展)下).

请参阅Ben Voigt的解决方案,该解决方案是一个简化版本boost::value_initialized,正如Litb在对Ben的回答的评论中指出的那样.这些文档对boost::value_initalized问题,解决方法以及各种编译器问题的一些缺陷进行了很好的讨论.

  • @BenVoigt - 关于错误报告的更新 - 刚从MS得到这个"我可以确认这确实是一个编译器错误.但是,鉴于我们的时间表和资源限制,我们不相信这个错误严重到足以在此时修复.但是,我们将考虑在将来的版本中修复此问题.感谢您抽出宝贵时间引起我们的注意!Andy Rich,Visual C++ QA" (2认同)

Ben*_*igt 5

我不认为需要模板元编程.尝试

template <class T>
void doit()
{
    struct initer { T t; initer() : t() {} } inited;
    T& t = inited.t;
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 非常好._____ (3认同)
  • @Michael,@ James,@ Ben,这是`boost :: value_init`:http://www.boost.org/doc/libs/1_42_0/libs/utility/value_init.htm.值得注意的是C++ 0x允许`T t {};` (2认同)