问题 可以抛出具有私有拷贝构造函数的对象吗?


我遇到了一些我不清楚的异常问题。在C ++中,当抛出一个对象时,它首先被复制到一个临时对象,然后临时对象被传递给捕获代码。该副本涉及使用对象的类复制构造函数。 AFAIK,这意味着如果一个类有一个私有拷贝构造函数,它就不能用作异常。但是,在VS2010中,以下代码编译并运行:

class Except
{
    Except(const Except& other) { i = 2; }
public:
    int i;
    Except() : i(1) {}
};

int main()
{
    try
    {
        Except ex1;
        throw ex1;          // private copy constructor is invoked
    }
    catch (Except& ex2)
    {
        assert(ex2.i == 2); // assert doesn't yell - ex2.i is indeed 2
    }
    return 0;
}

这合法吗?


12837
2018-04-11 09:54


起源

尝试添加打印或调试并查看调用顺序,可能事情并不像您认为的那样完全执行。 - selalerer
我对VS2010有同样的行为,但是失败了 这里 用gcc v4.3.4。 - hmjd
可能是临时对象是构造的,并且副本被优化掉了。与返回值优化类似。 - Bo Persson
@DumbCoder,它使用VS2010为我编译和执行。 - hmjd
@selalerer - 调试显示在预期的时间确实输入了私有拷贝c'tor。 @zabulus - 它没有编译,正如人们所期望的那样,但错误就在于 catch 线。我的问题是 throw。 - eran


答案:


这不合法。标准15.1 / 5

如果可以在不改变的情况下消除临时对象的使用   除了执行构造函数之外,程序的含义   和使用临时对象相关的析构函数   (12.2),然后可以直接初始化处理程序中的异常   使用throw表达式的参数。 当抛出的对象是一个   class对象,以及用于初始化的复制构造函数   临时副本无法访问,该程序格式不正确 (即使是   否则可以消除临时对象)。同样,如果   该程序是无法访问该对象的析构函数   形成不良(即使临时对象可能是其他情况   消除)。


13
2018-04-11 10:05



哇,太棒了,永远不会猜到它会发生。谢谢。 - Ravid Goldenberg


不,这不对。

15.1.5当抛出的对象是类对象时,应该可以访问复制/移动构造函数和析构函数,   即使复制/移动操作被省略


2
2018-04-11 10:06