提问人:Martin Ba 提问时间:2/20/2023 最后编辑:Martin Ba 更新时间:2/21/2023 访问量:130
C++ 结构作为函数参数与多个常量引用参数与 C++ 核心指南与性能?
C++ struct as function argument vs. multiple const ref parameters vs. C++ core guidelines vs. performance?
问:
我目前正在尝试决定是否“构造”一个相当长的参数集:
void fooCopy1(std::string const& source, std::string const& destination, std::string const& filter, std::string const& temp);
对此:
struct FooCopyArgs {
std::string source;
std::string destination;
std::string filter;
std::string temp;
};
void fooCopy2(FooCopyArgs const& args);
正如在另外两个问题中已经回答的那样:
重构它可能具有几个可读性/可维护性优势。有关其中的一堆,请参阅链接的问题。
然而,总的来说,我在C++中看到了这种方法的一个“大”问题,那就是在调用此函数之前始终必须复制字符串,而不是使用参数。const&
这将违反C++核心准则F.16“通过值传递廉价复制的类型,通过引用const传递其他类型”。
也就是说,通常由 传递的非廉价只读参数需要复制到结构中,这将是普遍的悲观情绪。const ref
(是的,结构本身将由 const ref 传递,但结构数据成员需要先复制。
例:
const string temp = ...;
const string filter = ...;
...
fooCopy2({"sourceItem", "targetItem", filter, temp});
对于 ,这是本地定义的参数值,这无关紧要。
但是,对于传递下来的参数,我们将有一个无关的副本,可以通过简单的方法避免。"sourceItem"
filter
temp
const&
免责声明:显然,在 99% 的情况下,性能影响甚至在最终应用程序中都无法观察到,但它仍然留下了不好的味道,尤其是在 F.16 等“基本”规则的上下文中。
问题:有没有聪明的方法可以解决这个问题,即:
- 有一个安全的结构作为参数类型(成员不安全;极易出现悬空引用)
const&
- 避免非廉价类型的无关副本
- 如果 severeal 函数使用此模式,则保持可组合性
附录:为什么使用成员不安全:const&
struct HasConstRef {
std::string const& member;
};
void f(HasConstRef const& arg) {
std::cout << arg.member << "\n";
}
HasConstRef arg_producer() {
HasConstRef result = { "there be dragons" };
return result; // UB
}
void f_call() {
f(arg_producer()); // *boom*, no diagnostic required
}
虽然我完全同意当前的答案,即可以正确使用 const-ref-membered 结构,但在没有任何编译器帮助的情况下,它也很容易被错误地使用。我宁愿不这样做。
我发现“难以正确使用”与“不可能错误使用”相去甚远。而“正常”的 const-ref 参数,就像普通数据成员一样,很难错误地使用(就 C++ 而言)。 另一方面,易于错误地使用。其他人似乎不同意:请参阅下面的答案。仍然欢迎替代方案。const& members
答:
那你为什么要删除?以下编译很好:const&
#include <string>
using string = std::string;
struct FooCopyArgs {
std::string const& source;
std::string const& destination;
std::string const& filter;
std::string const& temp;
};
void fooCopy2(FooCopyArgs const& args);
int main() {
const string temp = "";
const string filter = "";
fooCopy2({"sourceItem", "targetItem", filter, temp});
}
评论
FooCopyArgsWithConstRef
non_null<std::string*>
{&source, &destination, &filter, &temp}
FooCopyArgsWithConstRef version on the stack as a local variable
我不明白。你能举个例子吗?如果把一个局部变量放在main中,就没有区别了,反正创建一个临时的,它是一样的,只是变量的寿命会略有不同。FooCopyArgs
{...}
在这种情况下,我不会担心性能,而会更多地担心语义。如果项目确实属于一起,则应将它们组合成一个结构或类。换句话说,你希望你的类和结构具有高度的内聚力。
也许并且应该是类的成员,并且应该是同一类中的成员函数。据推测,并且不经常更改,而 和 做。filter
temp
fooCopy()
filter
temp
source
destination
顺便说一句,考虑重命名为更具描述性的名称。temp
评论
HasConstRef
"there be dragons"
arg_producer()
arg_producer