C++ 结构体作为函数参数 vs. 多个 const ref 参数 vs. C++ 核心指南 vs. 性能?

Mar*_* Ba 2 c++ parameter-passing pass-by-const-reference

我目前正在尝试决定是否“结构化”相当长的参数集:

void fooCopy1(std::string const& source, std::string const& destination, std::string const& filter, std::string const& temp);
Run Code Online (Sandbox Code Playgroud)

对此:

struct FooCopyArgs {
    std::string source;
    std::string destination;
    std::string filter;
    std::string temp;
};
void fooCopy2(FooCopyArgs const& args);
Run Code Online (Sandbox Code Playgroud)

正如在另外两个问题中已经回答的那样:

重构它可能有几个可读性/可维护性的优点。对于其中的一些问题,请参阅链接的问题。

总的来说,我在 C++ 中看到了这种方法的一个“大”问题,那就是在调用此函数之前始终必须复制字符串,而不是使用const&参数。

这将违反C++ 核心指南 F.16 “按值传递廉价复制类型,并通过引用 const 传递其他类型”。

也就是说,通常由 传递的非廉价只读参数const ref需要复制到结构中,这将是一种普遍的悲观化。

(是的,结构本身将通过 const ref 传递,但需要首先复制结构数据成员。)

例子:

const string temp = ...;
const string filter = ...;
...
fooCopy2({"sourceItem", "targetItem", filter, temp});
Run Code Online (Sandbox Code Playgroud)

对于"sourceItem",这是一个本地定义的参数值,这并不重要。然而,对于传递的参数filtertemp我们将有一个无关的副本,可以通过简单的const&方法来避免。

免责声明:显然,在 99% 的情况下,在最终应用程序中甚至不会观察到性能影响,但它仍然会留下不好的印象,尤其是。在诸如 F.16 之类的“基本”规则的背景下。

问题:有没有什么巧妙的方法可以解决这个问题,即:

  • 有一个安全的结构作为参数类型(const&成员不安全;极容易出现悬空引用)
  • 避免非廉价类型的无关副本
  • 如果多个函数使用此模式,请保持可组合性

附录:为什么使用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
}
Run Code Online (Sandbox Code Playgroud)

虽然我完全同意当前的答案,即 const-ref-membered 结构可以正确使用,但如果没有编译器的任何帮助,它也非常容易错误使用。我宁愿不这样做。

我发现“很难错误使用”与“不可能错误使用”相距甚远。而“普通”const-ref 参数,就像普通数据成员一样,很难错误地使用(就 C++ 而言)。const& members另一方面,它们很容易被错误地使用。其他人似乎不同意:请参阅下面的答案。替代方案仍然受欢迎。

Kam*_*Cuk 5

Sooo为什么要删除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});
}
Run Code Online (Sandbox Code Playgroud)