【发布时间】:2011-09-19 23:20:21
【问题描述】:
我最近遇到了一个案例,我有一个 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 只能用于调试,而不能用于发布。
我正在寻找编译时解决方案。如果做不到这一点,我正在寻找最佳的运行时解决方案。
【问题讨论】:
-
如果您使用的是 GCC,我认为它有
-Wunused-result标志来启用警告。 -
我的建议是选择一个更好的方法名称。如果我读到
a.add(b),我会立即想到mutator。a.newListWithHead(b)或类似的东西怎么样,取决于实际发生的情况?不像add那样简洁,但添加并不是你在这里真正要做的。 -
我喜欢 spong 改名的想法。例如,您可以将其更改为
a + b(如果这样做有意义的话)然后每个人都会知道“a + b”不会修改a,但他们可以很容易地写成“a += b”来获得他们想要的效果(我认为)。 -
@Sam 和其他人,我正在使用 MSVC 2010 和 GCC 3(我想这将是带有 Xcode 4 的 Clang)。
-
-Wunused-result 倾向于喷出。用户不会在 spew 中看到关于 a.add(b) 的警告。