c++ - 使用代理对象延迟更新与“使用自定义构造和销毁避免未命名对象”
问题描述
我有一个类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);
}
它产生以下输出,看起来正是我想要的:
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);
比
x.set_a(1)->set_b(2);
我建议将 setter 设为私有并添加一个朋友事务类,以便修改对象如下所示:
complicated x;
{
transaction t(x);
t.set_a(1);
t.set_b(2);
// implicit commit may be also done in destructor
t.commit();
}
如果transaction
将是修改的唯一方法complicated
- 用户将更倾向于在一个事务中调用多个设置器。
推荐阅读
- c# - 带有 .NET Core 3.1 的 C# 嵌入式资源图像
- ubuntu - 在 GitHub Actions Ubuntu runners 上安装 libzmq3-dev 时遇到问题
- javascript - 如何在单击子组件中的按钮时更改父组件内容?
- osquery - osquery 按需 yara 扫描错误:没有这样的列:模式
- magento - Magento 多种运输方式
- sql - 有什么方法可以避免在 sql plus 中加入笛卡尔连接
- python - 执行选择组合并阻止 pytest 运行所有参数化组合
- azure - Azure 逻辑应用开始限制工作?
- sql - 具有 where 条件的窗口函数(条件 row_number())
- angular - 在目标路由保护中重定向时如何停止双重 canDeactivate 调用?