【问题标题】:warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)警告 C4290:C++ 异常规范被忽略,除了指示函数不是 __declspec(nothrow)
【发布时间】:2014-03-19 10:21:39
【问题描述】:

在 VS 2008 中编译我的 vc++ 代码时生成的这个特殊警告让我困扰了一段时间。在浏览 SO 和微软论坛中有关此警告的相关帖子时,建议使用 pragma 警告禁用警告,但是有没有办法在没有警告 pragma 的情况下解决此问题?

class CBLockException : public CBException
{
public:
    // Constructor
    CBLockException();
    CBLockException(const char *tag);
    CBLockException(const char *func, const char *tag, const char *msg = NULL);
};


class CLASS_DECL_BASEOBJECTS CBLock : public CBObject
{
public:

    enum Locktype { READLOCK, WRITELOCK };

    CBLock() throw (CBLockException*);   // C4290
    virtual ~CBLock();

    void Lock(Locktype lockType = WRITELOCK);
    void Unlock(Locktype lockType = WRITELOCK);

private:
    class LockImplementation;

    LockImplementation *lockImp;
};


class CBLock::LockImplementation
{

public:
    LockImplementation() throw (CBLockException*);  //C4290
    ~LockImplementation();

    CRITICAL_SECTION csExclusive;                      
    CRITICAL_SECTION csReader;                         
    HANDLE           hevReadDone;                        
    int              cReader;                               
};

【问题讨论】:

  • “解决问题”是什么意思? MSVC 没有完全实现异常规范的强制语义(这是警告告诉你的)。所以如果你想要完整的语义,你需要使用不同的编译器。如果你想继续使用 MSVC 编译器,并且你不介意它对异常规范的不符合处理,那么通过禁用警告来确认这一点。无论哪种方式,问题都已解决。
  • 动态异常规范在 C++ 中已被弃用,因此最好的解决方案是将它们从您的代码中删除。

标签: visual-c++


【解决方案1】:

但是有没有办法在没有警告编译指示的情况下解决这个问题?

是的。删除throw 规范。它不会做你认为它会做的事情。相反,它大多是无用的。

具体来说,写作:

CBLock() throw (CBLockException*);
…
CBLock::CBLock() { /* … */ }

本质上等价于

CBLock();
…
CBLock::CBLock() {
    try {
        /* … */
    } catch(CBLockException*&) { // Yes, like this! Stop throwing exceptions by pointer, please!
        throw;
    } catch(...) {
        throw std::bad_exception();
    }
}

(实际上,使用构造函数它相当于函数 try 块,但我不想用另一个 C++ 疣进一步复杂化)

特别注意它确实真正检查该块没有抛出任何其他类型的异常。它唯一能做的就是将任何其他异常转换为完全无用的std::bad_exception,在此过程中丢弃任何有用的信息。

建议的修复方法是将任何 throw 声明转换为文档 cmets!

还要注意,这甚至适用于throw() 规范。唯一有用的是 C++11 中引入的 nothrow 规范,它实际上检查函数永远不会抛出任何 C++ 异常,它是早期 MSC++ 特定的 __declspec(nothrow) 等价物。

【讨论】:

  • 不,它不是没用的。仅仅因为微软忽略该标准并不意味着它没有必要。例如,SWIG 广泛使用它,因为它是确定函数是否真的引发异常的唯一方法。 #pragma warning(disable : 4290) 是唯一正确的方法。
  • @MichaelMaenz,列表类型的表单(生成这些警告的原因)在 C++17 中完全删除。它不再是有效的 C++ 语法。
【解决方案2】:

转到项目属性页 -> 配置属性 -> C/C++ -> 高级 -> 禁用特定警告 -> 编辑

输入要禁用的警告代码,用分号分隔(在您的情况下为 4290,不带前导“C”)

来源:http://msdn.microsoft.com/en-us/library/jj715718.aspx

【讨论】:

    猜你喜欢
    • 2017-06-01
    • 2011-01-12
    • 1970-01-01
    • 2015-03-10
    • 2021-01-15
    • 2014-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多