在访问者上下文中,我需要在访问子项之前临时设置变量,然后再恢复该变量。我正在使用以下代码,但我确信有更优雅和正确的方法来执行此操作:
template <typename TYPE> class TemporaryAssignment {
protected:
TYPE& mVariable;
TYPE mOriginalValue;
public:
TemporaryAssignment(TYPE& inVariable, TYPE inValue)
: mVariable(inVariable), mOriginalValue(inVariable) {
mVariable = inValue;
}
~TemporaryAssignment(void) {
mVariable = mOriginalValue;
}
};
这允许我写下类似的内容:
{
...
TemporaryAssignment<string> t(myVariable, myTemporaryValue);
visitChildren();
...
}
// previous value of myVariable is restored
当临时赋值对象超出范围时,该变量将恢复为其先前的值。有什么更好的方法呢?
答案 0 :(得分:6)
除了析构函数可以抛出之外,对我来说还不错,这很糟糕。 swap
具有原始值而非分配(编辑:此处理std::string
,但请查看与string
用户不太友好的类可能出现问题的注释。
如果你从代码的这一部分稍微退一步,也许你可以找到一种不需要设置临时值的方法。对象中的共享可变状态可能是坏的,原因与可变全局变量是坏的相同,但程度较小,因为它只会弄乱你的类,而不是弄乱你的整个程序。
例如,您可以复制整个对象,为变量设置新值并访问副本而不是访问自己。显然,这不一定是可能的或有效的,你必须根据具体情况寻找替代方案。就孩子们而言,也许副本可能很浅(即引用相同的子对象),这可能足以使其便宜。
关于使用情况,您可以推断出类似这样的类型(未经测试的代码):
template <typename T, typename ARG>
TemporaryAssignment<T> temp_value(T &var, ARG &&newvalue) {
return TemporaryAssignment(var, std::forward<ARG>(newValue));
}
用法:
auto t = temp_value(myVariable, myTemporaryValue);
然后你需要一个TemporaryAssignment的移动构造函数:
template <typename TYPE> class TemporaryAssignment {
// change data member
TYPE *mVariable;
TYPE mOriginalValue;
public:
TemporaryAssignment(TYPE &inVariable, TYPE inValue)
: mVariable(&inVariable), mOriginalValue(std::move(inVariable)) {
*mVariable = std::move(inValue);
}
TemporaryAssignment(TemporaryAssignment &&rhs) {
mOriginalValue = std::move(rhs.mOriginalValue);
mVariable = rhs.mVariable;
rhs.mVariable = 0;
}
~TypeAssignment() {
using std::swap;
if (mVariable) {
swap(*mVariable, mOriginalValue);
}
}
// can't remember whether this is needed
TemporaryAssignment(const TemporaryAssignment &) = delete;
TemporaryAssignment &operator=(const TemporaryAssignment &) = delete;
TemporaryAssignment &operator=(TemporaryAssignment &&) = delete;
};
我想过为operator=
指定TemporaryAssignment
,以便使用看起来像是一项任务,但我没有提出任何好处。
auto t = (temporary(myVariable) = myTemporaryValue);
似乎是合理的,但您可能不希望TemporaryAssignment
定义operator=
,因为其含义为:
t = otherTemporaryValue;
不一定清楚,可能不应该被允许。也许从temporary
返回第二个类,并从TemporaryAssignment
返回operator=
。
答案 1 :(得分:2)
swap
不是最佳解决方案,因为如果TYPE
有std::string
成员,则崩溃问题也可能发生。
我想我们可以使用这样的方法:
char buffer[sizeof(TYPE)];
memcpy(buffer, &mVariable, sizeof(TYPE));
memcpy(&mVariable, &mOriginalValue, sizeof(TYPE));
memcpy(&mOriginalValue, buffer, sizeof(TYPE));
答案 2 :(得分:0)
补充Steve Jessop的答案。从RIIA(或RAII)的角度来看,类的析构函数可能最终获取资源(内存),它应该只释放资源。为了避免这种情况,您可能会想到使用一个在正确的时间指向正确对象的myVar,因此只能在构造或获取时正确创建新对象,并且在发布时只会发生删除和指针重新分配