Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 不可复制对象和值初始化:g++;vs msvc_C++_Gcc_Visual C++_Value Initialization - Fatal编程技术网

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

C++ 不可复制对象和值初始化:g++;vs msvc,c++,gcc,visual-c++,value-initialization,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 noncop

我看到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_;
};
以及使用值初始化的模板,以便即使类型为POD,该值也将获得已知值:

template <class T>
void doit()
{
    T t = T();
    ...
}
模板
void doit()
{
T=T();
...
}
并尝试将它们结合起来使用:

doit<noncopyable>();
doit();
从VC++9.0开始,这在msvc上运行良好,但在我测试过的每个g++版本(包括4.5.0版)上都失败,因为复制构造函数是私有的

两个问题:

  • 哪种行为符合标准
  • 关于如何在gcc中解决这一问题的任何建议(需要明确的是,将其更改为
    T;
    都不是一个可接受的解决方案,因为这会破坏POD类型)

  • 另外,我发现boost::noncopyable也存在同样的问题。

    您在MSVC中看到的行为是一个扩展,尽管在下一页(我的重点部分)中以一种迂回的方式对其进行了描述:

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

    • 创建与正在初始化的对象类型相同的临时对象
    • 将临时对象复制到对象
    在编译器可以执行这些步骤之前,构造函数必须是可访问的。尽管编译器在大多数情况下可以消除临时创建和复制步骤,但不可访问的复制构造函数会导致等号初始化失败(在/Za、/Ze(禁用语言扩展)

    正如litb在对Ben回答的评论中指出的,解决方案是的简化版本。
    boost::value_initialized
    的文档对问题、解决方法以及各种编译器问题的一些缺陷进行了大量讨论。

    有§12.8/14:

    如果隐式使用了对象的复制构造函数或复制赋值运算符,并且无法访问特殊成员函数,则程序的格式是错误的

    还有§12.8/15:

    当满足某些条件时,即使对象的复制构造函数和/或析构函数有副作用,也允许实现忽略类对象的复制构造

    因此,问题是,如果实现忽略了对复制构造函数的调用(这显然是允许的),那么复制构造函数是否实际被使用

    根据§3.2/2,答案是肯定的:

    即使实现实际上省略了调用,也会使用复制构造函数


    您是否看到了在MSVC中使用/Wall编译时发生的情况?它说明了关于您的课程的以下内容:

    nocopy.cc(21) : warning C4625: 'noncopyable' : copy constructor could not be
    generated because a base class copy constructor is inaccessible
    nocopy.cc(21) : warning C4626: 'noncopyable' : assignment operator could not be
    generated because a base class assignment operator is inaccessible
    
    GCC补救措施: 为
    noncopyable
    (最好是赋值操作符!)创建一个复制构造函数,该构造函数尽其所能从
    noncopyable\u base
    复制信息,即调用没有参数的
    noncopyable\u base
    的构造函数(因为这是
    noncopyable
    唯一可访问的构造函数)然后从
    noncopyable\u base
    复制任何数据。然而,根据
    noncopyable_base
    的定义,似乎没有数据可复制,因此将
    noncopyable_base()
    简单添加到新的
    noncopyable(const noncopyable&)
    函数的初始值设定项列表中应该可以工作


    注意MSVC对你的程序所说的话。另外请注意,如果您使用
    T()
    而不是
    T=T()
    ,则是由MSVC生成的,尽管GCC很乐意接受这两种方式,而不发出任何警告。

    我认为不需要模板元编程。试一试

    template <class T>
    void doit()
    {
        struct initer { T t; initer() : t() {} } inited;
        T& t = inited.t;
        ...
    }
    
    模板
    void doit()
    {
    结构initer{T;initer():T(){}}inited;
    T&T=初始的.T;
    ...
    }
    
    我很确定MSVC是不符合要求的,让我来看看报价。(我认为只要拷贝构造函数可用,编译器就可以省略拷贝。)Comeau()支持GMan。即使是最新的VC版本,我也在这方面看到了一些bug。当你说“解决”时,有两个函数模板可以吗?一个用于POD类型,一个用于非POD类型(并使用SFINAE在它们之间进行选择)?几乎“不可能”得到你想要的。C++是非常强大的。在这种情况下,解决办法甚至不是所有的邪恶(尽管比原始的更丑陋,当然)。这就是为什么我变得如此犹豫,用C++来说某事是不可能的…有一半的时候我会说,有人来证明我错了。谢谢。虽然看起来MSVC有更大的问题。当private copy构造函数和operator=放在基类中(实现boost::noncopyable的方式)时,MSVC总是允许等号初始化。有人知道如何向MS编译器团队报告一个bug吗?并在这里提到bug编号(或者更好的是,链接),这样我们就可以对它进行投票。@BenVoigt-bug#is 552586()当无法访问复制构造函数时,该bug是否真的允许复制构造,或者只为构造提供一种替代(非标准)语法,以避免“最麻烦的解析”? 我的意思是,它是否只删除了复制构造函数而没有执行可访问性检查,或者它也从一个本身不是由构造函数调用临时形成的右值复制了构造?@BenVoigt-bug报告更新-刚从MS获得此消息“我可以确认这确实是一个编译器错误。然而,考虑到我们的日程安排和资源限制,我们认为这个bug还不够严重,不能保证在这个时候修复。然而,我们将考虑在将来的版本中修复这一点。感谢您抽出时间让我们注意到这一点!Andy Rich,Visual C++ QA“<代码> t())