问题描述
我发现 g++ 和 msvc 在初始化不可复制对象的值方面有一些不同的行为.考虑一个不可复制的类:
I'm seeing some different behavior between g++ and msvc around value initializing non-copyable objects. Consider a class that is non-copyable:
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_;
};
以及使用值初始化的模板,以便即使类型为 POD 值也会获得已知值:
and a template that uses value initialization so that the value will get a known value even when the type is POD:
template <class T>
void doit()
{
T t = T();
...
}
并尝试将它们一起使用:
and trying to use those together:
doit<noncopyable>();
从 VC++ 9.0 开始,这在 msvc 上运行良好,但在我测试过的每个 g++ 版本(包括版本 4.5.0)上都失败了,因为复制构造函数是私有的.
This works fine on msvc as of VC++ 9.0 but fails on every version of g++ I tested this with (including version 4.5.0) because the copy constructor is private.
两个问题:
- 哪些行为符合标准?
- 关于如何在 gcc 中解决此问题的任何建议(并且明确地说,将其更改为
T t;
是不可接受的解决方案,因为这会破坏 POD 类型).
- Which behavior is standards compliant?
- Any suggestion of how to work around this in gcc (and to be clear, changing that to
T t;
is not an acceptable solution as this breaks POD types).
附言我看到 boost::noncopyable 也有同样的问题.
P.S. I see the same problem with boost::noncopyable.
推荐答案
您在 MSVC 中看到的行为是一个扩展,尽管它在下一页(重点是我的)中以迂回的方式进行了记录http://msdn.microsoft.com/en-us/library/0yw5843c.aspx:
The behavior you're seeing in MSVC is an extension, though it's documented as such in a roundabout way on the following page (emphasis mine) http://msdn.microsoft.com/en-us/library/0yw5843c.aspx:
等号初始化语法与函数式语法不同,尽管生成的代码在大多数情况下是相同的.不同之处在于,当使用等号语法时,编译器的行为就好像发生了以下事件序列:
The equal-sign initialization syntax is different from the function-style syntax, even though the generated code is identical in most cases. The difference is that when the equal-sign syntax is used, the compiler has to behave as if the following sequence of events were taking place:
- 创建一个与正在初始化的对象类型相同的临时对象.
- 将临时对象复制到对象中.
在编译器执行这些步骤之前,构造函数必须是可访问的.尽管编译器在大多数情况下可以消除临时创建和复制步骤,但不可访问的复制构造函数会导致等号初始化失败(在/Za、/Ze(禁用语言扩展)下).
The constructor must be accessible before the compiler can perform these steps. Even though the compiler can eliminate the temporary creation and copy steps in most cases, an inaccessible copy constructor causes equal-sign initialization to fail (under /Za, /Ze (Disable Language Extensions)).
参见 Ben Voigt 的回答 解决方法是 boost::value_initialized
,正如 litb 在对 Ben 的回答的评论中指出的那样.boost::value_initalized
的文档对问题、解决方法和各种编译器问题的一些陷阱进行了很好的讨论.
See Ben Voigt's answer for a workaround which is a simplified version of boost::value_initialized
, as pointed out by litb in a comment to Ben's answer. The docs for boost::value_initalized
has a great discussion of the problem, the workaround, and some of the pitfalls of various compiler issues.
这篇关于不可复制的对象和值初始化:g++ 与 msvc的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!