我最近遇到一个案例,我有一个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&lt;&gt;是仅调试和无操作版本。
我正在寻找编译时解决方案。如果做不到这一点,我正在寻找最佳的运行时解决方案。
答案 0 :(得分:8)
这是GCC和Clang中(documentation)的函数属性,但它不可移植到例如MSVC。
class Foo { ...
__attribute__((warn_unused_result))
Foo add(Foo const & x) const;
}
文档说明它已在realloc
上使用,例如,但它不会出现在我系统上的任何其他标准函数中。
您可能还有兴趣使用Clang静态分析器,它可以跟踪函数调用中的数据流,并且可以为您提供更好的警告。
答案 1 :(得分:7)
对于Microsoft VC ++,有_Check_return_
注释:http://msdn.microsoft.com/en-us/library/ms235402(v=VS.100).aspx
答案 2 :(得分: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;
}
};