返回对象的攻击子具有副作用
Return object whose destructor has side effects
我们有一个类,可以帮助我们将数据发送到telegraf/influxdb(即用于监视)。看起来很像这样:
class TelegrafSend {
public:
// // Constructor does some default stuff based on binary name and context.
TelegrafSend();
// Destructor sends the object.
~TelegrafSend();
// Exists in a couple variants. Probably could have been a template.
void AddTag(const std::string& tag_name, const std::string& tag_value);
// Same.
void AddField(const std::string& field_name, const int field_value);
};
要清楚,看起来像这样:
TelegrafSend TelegrafSend::AddField(const string& field_name, const int field_value) {
fields_[field_name] = to_string(field_value);
sent_ = false;
return *this;
}
这很好:
TelegrafSend telegraf;
telegraf.AddTag("a_tag", "a_value");
telegraf.AddField(kTelegrafCount, 1);
并且由于它不在范围时,它将被发送,这是一个不错的行为,因为一个函数可以在执行时添加几个指标,并且从函数中的所有退出会导致对象发送。
现在我有一个聪明的主意:
class TelegrafSend {
public:
// // Constructor does some default stuff based on binary name and context.
TelegrafSend();
// Destructor sends the object.
~TelegrafSend();
// Exists in a couple variants. Probably could have been a template.
TelegrafSend AddTag(const std::string& tag_name, const std::string& tag_value);
// Same.
TelegrafSend AddField(const std::string& field_name, const int field_value);
};
,所以我可以写
TelegrafSend telegraf.AddTag("a_tag", "a_value").AddField(kTelegrafCount, 1);
这里的问题是我正在创建临时工,因此,尽管这最终起作用,但每个退货都会创建一个临时性,该临时性被摧毁并因此发送到Telegraf。对于InfluxDB而言,这确实效率低下,甚至没有谈论C 中的不良练习。
我尝试过一些关于返回rvalue参考的变体,但是我要么尝试返回对临时变量或堆栈变量的参考,要么做一些同样愚蠢的事情。我在生产中发现的示例做了很多其他事情,以至于我不确定该怎么做。
有没有指导这种模式的最佳实践?还是我想做一些我不应该做的句法?
您必须在这些方法中返回对自我的引用,而不是创建新对象。
实施移动构造函数也可能考虑。
class TelegrafSend {
public:
TelegrafSend();
~TelegrafSend();
TelegrafSend(const TelegrafSend&) = delete;
TelegrafSend& operator = (const TelegrafSend&) = delete;
TelegrafSend(TelegrafSend&&); // possibly = delete;
TelegrafSend& operator = (TelegrafSend&&); // possibly = delete;
// Exists in a couple variants. Probably could have been a template.
TelegrafSend& AddTag(const std::string& tag_name, const std::string& tag_value)
{
/*..*/
return *this;
}
// Same.
TelegrafSend& AddField(const std::string& field_name, const int field_value)
{
/*..*/
return *this;
}
};
然后您可以使用:
TelegrafSend{}.AddTag("a_tag", "a_value").AddField(kTelegrafCount, 1);
我将以std::optional
的形式实现并提供一个移动构造函数,以便在破坏者期间提供自动"有效性"指标。
请注意,从可选的移动不会清空它,它只会将内容移出,因此您必须重置可选的。
完成示例:
#include <optional>
#include <string>
#include <iostream>
struct TelegrafSend
{
// // Constructor does some default stuff based on binary name and context.
TelegrafSend();
TelegrafSend(TelegrafSend&& other);
TelegrafSend(TelegrafSend const& ) = delete;
TelegrafSend& operator=(TelegrafSend const& ) = delete;
TelegrafSend& operator=(TelegrafSend && ) = delete;
// Destructor sends the object.
~TelegrafSend();
TelegrafSend& AddTag(const std::string& tag_name, const std::string& tag_value);
TelegrafSend& AddField(const std::string& field_name, const int field_value);
private:
struct Impl
{
std::string narrative;
void more(std::string const& s)
{
if (!narrative.empty())
narrative += 'n';
narrative += s;
}
void emit()
{
if (narrative.empty())
std::cout << "{empty}n";
else
std::cout << narrative << 'n';
}
};
std::optional<Impl> impl_;
};
TelegrafSend::TelegrafSend()
: impl_(Impl())
{
}
TelegrafSend::TelegrafSend(TelegrafSend&& other)
: impl_(std::move(other.impl_))
{
other.impl_.reset();
}
TelegrafSend::~TelegrafSend()
{
if(impl_.has_value())
impl_->emit();
}
TelegrafSend& TelegrafSend::AddTag(const std::string& tag_name, const std::string& tag_value)
{
auto s = "Tag : " + tag_name + " : " + tag_value;
impl_->more(s);
return *this;
}
TelegrafSend& TelegrafSend::AddField(const std::string& field_name, const int field_value)
{
auto s = "Field : " + field_name + " : " + std::to_string(field_value);
impl_->more(s);
return *this;
}
auto test(TelegrafSend ts = {}) -> TelegrafSend
{
ts.AddTag("foo", "bar").AddField("baz", 6);
return ts;
}
int main()
{
{
test(), std::cout << "hellon";
}
std::cout << "worldn";
}
预期输出:
hello
Tag : foo : bar
Field : baz : 6
world
https://coliru.stacked-crooked.com/a/755d3d161b9d48b3
相关文章:
- C++Brute Force攻击函数不会返回结果
- PostgresSQL - SQL Ready 语句与字符串转义,防止 SQL 注入攻击
- 复制构造函数的奇怪副作用
- AES ECB已知文本攻击
- 程序只适用于包含(无副作用)cout声明
- 缓冲区溢出怎么会成为黑客的攻击
- 为什么评估一个表达可能会产生副作用
- strncmp 有副作用吗?
- 具有必要副作用的静态初始化被优化掉了
- 使用运营商New分配的数据结构是否有任何副作用
- 操作员的排序规则和副作用
- 您可以在不调用构造函数的情况下调用攻击器吗?
- C 可以使destuructor不称为班级成员和基类攻击方的灾难
- 如果 LTO 中的代码依赖于其构造的副作用,是否允许 LTO 删除未使用的全局对象?
- 默认参数中的 c++ new 运算符及其副作用
- 使用 gcc 的 -fno-math-errno 可能有什么副作用?
- 攻击者未调用
- 为什么在任务后打电话给攻击函数
- 如果(玩家[P] .setCoin(Gameboard,Input))将其命名为“在线”游戏板的攻击函数)
- 返回对象的攻击子具有副作用