有没有一个好的方法来确保 C++函数结果不被忽略?
我最近遇到一个案例,我有一个 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<>仅用于调试,不可用于发布。
我正在寻找编译时解决方案。如果做不到这一点,我正在寻找最好的运行时解决方案。
I ran into a case recently where I had a const member function performing an operation and returning a result. For example,
class Foo { ...
Foo add(Foo const & x) const;
}
But someone else was inadvertently calling it like it was updating the this
object (ignoring the result):
Foo a = ...;
Foo b = ...;
a.add(b);
(This bug was actually introduced by an imperfect refactoring.)
Is there a way to make the last line above trigger an error or a warning? The next best thing would be a run-time catch, which is mostly addressed by the following template. However, it kills the return value optimization, as seen by the counter result.
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;
}
I suppose I can ameliorate the inefficiency by using a macro so that MustTake<> is debug only and a no-op for release.
I am looking for a compile-time solution. Failing that, I am looking for the best run-time solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这就是 GCC 和 Clang 中函数属性的用途(文档),但它不能移植到例如MSVC。
文档说它用于
realloc
例如,但它没有出现在我系统上的任何其他标准函数上。您可能还对使用 Clang 静态分析器感兴趣,它可以跟踪函数调用之间的数据流,并可以为您提供更好的警告。
This is what function attributes are for (documentation) in GCC and Clang, but it's not portable to e.g. MSVC.
The documentation says it's used on
realloc
for example, but it doesn't appear on any other standard functions on my system.You may also be interested in using the Clang static analyzer, which tracks data flow across function calls and can give you better warnings.
对于 Microsoft VC++,有
_Check_return_
注释:http://msdn.microsoft.com/en-us/library/ms235402(v=VS.100).aspxFor Microsoft VC++, there is the
_Check_return_
annotation: http://msdn.microsoft.com/en-us/library/ms235402(v=VS.100).aspx如果函数的调用者不忽略返回值很重要,则可以按如下方式使用模板
dont_ignore
BEFORE:
AFTER:
当函数的调用者不使用返回值时,抛出异常。
dont_ignore
的定义:If it is important that a return value not be ignored by the caller of a function, the template
dont_ignore
may be used as followsBEFORE:
AFTER:
When the caller of the function does not use the return value, an exception is thrown. Definition of
dont_ignore
: