7

我最近遇到了一个案例,我有一个 const 成员函数执行操作并返回结果。例如,

class Foo { ...
    Foo add(Foo const & x) const;
}

但是其他人无意中调用了它,就像它正在更新this对象一样(忽略结果):

Foo a = ...;
Foo b = ...;
a.add(b);

(这个错误实际上是由不完美的重构引入的。)

有没有办法让上面的最后一行触发错误或警告?下一个最好的事情是运行时捕获,这主要由以下模板解决。但是,它会破坏返回值优化,如计数器结果所示。

template<typename T>
class MustTake {
    T & obj;
    bool took;
public:
    MustTake(T o) : obj(o), took(false) {}
    ~MustTake() { if (!took) throw "not taken"; }
    operator T&() { took = true; return obj;}
};

struct Counter {
    int n;
    Counter() : n(0) {}
    Counter(Counter const & c) : n(c.n+1) {}
    ~Counter() {}
};

Counter zero1() {
    return Counter();
}

MustTake<Counter> zero2() {
    return Counter();
}

int main() {
    Counter c1 = zero1();
    printf("%d\n",c1.n);    // prints 0
    Counter c2 = zero2();
    printf("%d\n",c2.n);    // prints 1
    zero1();    // result ignored
    zero2();    // throws
    return 0;
}

我想我可以通过使用宏来改善效率低下,以便 MustTake<> 仅用于调试并且对发布无操作。

我正在寻找一个编译时解决方案。如果做不到这一点,我正在寻找最佳的运行时解决方案。

4

3 回答 3

8

这就是 GCC 和 Clang 中(文档)的功能属性,但它不能移植到例如 MSVC。

class Foo { ...
    __attribute__((warn_unused_result))
    Foo add(Foo const & x) const;
}

文档说它realloc 用于例如,但它没有出现在我系统上的任何其他标准功能上。

您可能还对使用 Clang 静态分析器感兴趣,该分析器跟踪函数调用之间的数据流并可以为您提供更好的警告。

于 2011-06-22T00:22:40.873 回答
7

对于 Microsoft VC++,有_Check_return_注释: http: //msdn.microsoft.com/en-us/library/ms235402 (v=VS.100).aspx

于 2011-06-22T00:27:29.890 回答
0

如果函数调用者不忽略返回值很重要,则dont_ignore可以按如下方式使用模板

前:

int add( int x, int y )
{
    return x + y;
}

后:

dont_ignore<int> add( int x, int y )
{
    return x + y;
}

当函数的调用者不使用返回值时,就会抛出异常。的定义dont_ignore

template<class T>
struct dont_ignore
{
    const T     v;
    bool        used;

    dont_ignore( const T& v )
        :  v( v ), used( false )
    {}

    ~dont_ignore()
    {
        if ( !used )
            throw std::runtime_error( "return value not used" );
    }

    operator T()
    {
        used = true;
        return v;
    }
};
于 2017-04-13T07:55:29.447 回答