j00*_*0hi 3 c++ c++11 c++14 c++17
我有一个类complicated,其中包含修改一些内部状态的各种设置器。内部状态修改可能很昂贵,所以我不想经常这样做。特别是,如果几个 setter 被立即连续调用,我想在这些 setter 调用的最后一次之后只执行一次内部状态的昂贵更新。
我已经通过代理解决了(或“解决了”?)这个要求。以下将是一个最小的工作代码示例:
#include <iostream>
class complicated
{
public:
class proxy
{
public:
proxy(complicated& tbu) : to_be_updated(&tbu) {
}
~proxy() {
if (nullptr != to_be_updated) {
to_be_updated->update_internal_state();
}
}
// If the user uses this operator, disable update-call in the destructor!
complicated* operator->() {
auto* ret = to_be_updated;
to_be_updated = nullptr;
return ret;
}
private:
complicated* to_be_updated;
};
public:
proxy set_a(int value) {
std::cout << "set_a" << std::endl;
a = value;
return proxy(*this);
}
proxy set_b(int value) {
std::cout << "set_b" << std::endl;
b = value;
return proxy(*this);
}
proxy set_c(int value) {
std::cout << "set_c" << std::endl;
c = value;
return proxy(*this);
}
void update_internal_state() {
std::cout << "update" << std::endl;
expensive_to_compute_internal_state = a + b + c;
}
private:
int a;
int b;
int c;
int expensive_to_compute_internal_state;
};
int main()
{
complicated x;
x.set_a(1);
std::cout << std::endl;
x.set_a(1)->set_b(2);
std::cout << std::endl;
x.set_a(1)->set_b(2)->set_c(3);
}
Run Code Online (Sandbox Code Playgroud)
它产生以下输出,看起来正是我想要的:
set_a
更新SET_A
set_b
更新SET_A
set_b
set_c
更新
我的问题是:我的方法是否合法/最佳实践?
是否可以依赖proxy将在分号处销毁的临时对象(即返回的对象)?
我之所以这么问是因为出于某种原因我对此有不好的感觉。也许我的不好的感觉只是来自 Visual Studio 的警告,它说:
警告 C26444 避免使用自定义构造和销毁的未命名对象 (es.84)。
但也许/希望我的坏情绪是不合理的,可以忽略该警告?
最让我烦恼的是:是否有任何情况下update_internal_state不会调用该方法(可能是由于滥用我的类或某些编译器优化或其他原因)?
最后:有没有更好的方法来实现我试图用现代 C++ 实现的目标?
我认为你的解决方案是合法的,但它有一个缺点,它对代码的用户隐藏,更新很昂贵,所以人们更有可能写:
x.set_a(1);
x.set_b(2);
Run Code Online (Sandbox Code Playgroud)
比
x.set_a(1)->set_b(2);
Run Code Online (Sandbox Code Playgroud)
我建议将 setter 设为私有并添加一个朋友事务类,以便修改对象看起来像:
complicated x;
{
transaction t(x);
t.set_a(1);
t.set_b(2);
// implicit commit may be also done in destructor
t.commit();
}
Run Code Online (Sandbox Code Playgroud)
如果transaction将是唯一的修改方式complicated- 用户将更倾向于在一个事务中调用多个 setter。