如何在结构化回报中保存额外的复制结构?

How to save additional copy construct in structured return?

提问人:f1msch 提问时间:3/27/2023 最后编辑:Some programmer dudef1msch 更新时间:3/27/2023 访问量:74

问:

如果我想以结构化返回的方式返回一些结构。喜欢

pair<bool, vector<int>> get(const string &id) {
    vector<int> v;
    return {true, v};
}

struct st{};
pair<bool, st> get(const string &id) {
    st v;
    return {true, v};
}

并使用 like

auto [a1, b1] = get("1");   ---version1
auto &[a2, b2] = get("1");   ---version2

所以我有两个疑问,主要是考虑到复制结构的成本。 Q1: 在我的通话案例中和在内或外有区别吗? Q2:在复制到返回的过程中总是需要一次复制结构,但我认为至少在我的情况下这是不必要的。那么有没有办法节省复制构建的这段时间呢?version1version2getpair

C++ C++17 复制构造函数

评论

1赞 Some programmer dude 3/27/2023
如果创建了一对对象,则它将包含用于初始化对的数据的副本。由于该货币对将非常暂时并立即销毁,因此“version2”将为您提供悬而未决的引用。
0赞 j6t 3/27/2023
@Someprogrammerdude真的吗?引用延长了返回值的生存期。两个版本都很好。我也不期望两者之间的性能有任何差异,因为保证了返回值的复制省略。
0赞 PoneyUHC 3/27/2023
我猜您正在尝试应用一些语义而不是副本。 这个线程可能会对你有所帮助。在你的例子中,你可能想做一些类似的事情。我不像C++专家,所以不要犹豫纠正我movereturn std::move({true, std::move(v)})
0赞 Some programmer dude 3/27/2023
@j6t 实际上,它不应该建造。OP 需要它来延长使用寿命并构建。auto const&[a2, b2]
0赞 Some programmer dude 3/27/2023
致 OP:正如我上面提到的,您的“version2”甚至不应该构建。因此,这基本上只剩下一种选择(除非您对使用引用感到满意)。const

答:

1赞 A M 3/27/2023 #1

您需要了解 (N)RVO(((命名)返回值优化)和复制省略。

两者在CPP标准中都有很好的描述。

在大多数情况下,您无需担心 expensiv 复制操作。编译器将使用 RVO 来帮助您。但是,在一些极端情况下,RVO 将不起作用。再次,请阅读它。

您可以想象,编译器在函数之外为返回值创建空间,因此在调用方帧/作用域中。那么很明显,没有发生复制。

在这方面,最好先创建返回值,然后再返回它。然后 RVO 就会发生。

在返回对函数局部变量的引用时,您可能会遇到麻烦。这可能会产生悬空引用。(对函数结束后超出范围的函数局部变量的引用)。如果你想使用它,那么你可以使用引用。const

因此,您可以同时使用两者

#include <utility>
#include <string>
#include <vector>
using namespace std::string_literals;

std::pair<bool, std::vector<int>> get1(const std::string &id) {
    std::pair<bool, std::vector<int>> result{true, {}};
    return result;
}

struct st{};
std::pair<bool, st> get2(const std::string& id) {
    std::pair<bool, st> result{true, {}};
    return result;
}

int main() {
    const auto& [a1, b1] = get1("1"s);
    auto [a2, b2] = get1("1"s);

    const auto& [c1, d1] = get2("1"s);
    auto [c2, d2] = get2("1"s);

    return a1 and a2 and c1 and c2;
}

如果可能的话,建议使用该版本。const

Compiler Explorer 上查看输出

看看 Clang 做了什么 :-)