gpt4 book ai didi

c++ - 如果对象在下一步被破坏,为什么不自动 move ?

转载 作者:太空狗 更新时间:2023-10-29 20:03:27 25 4
gpt4 key购买 nike

如果函数返回这样的值:

std::string foo() {
std::string ret {"Test"};
return ret;
}

允许编译器 move ret,因为它不再被使用。这不适用于这样的情况:

void foo (std::string str) {
// do sth. with str
}

int main() {
std::string a {"Test"};
foo(a);
}

虽然 a 显然不再需要了,因为它在下一步中被销毁了,你必须这样做:

int main() {
std::string a {"Test"};
foo(std::move(a));
}

为什么?在我看来,这是不必要的复杂,因为右值和 move 语义很难理解,尤其是对于初学者。因此,如果您不必在标准情况下关心但无论如何都可以从 move 语义中受益(例如返回值和临时值),那就太好了。必须查看类定义以发现类是否支持 move 以及是否完全受益于 std::move(或使用 std::move 无论如何,希望它有时会有所帮助。如果您使用现有代码,它也容易出错:

int main() {
std::string a {"Test"};
foo(std::move(a));

// [...] 100 lines of code
// new line:
foo(a); // Ups!
}

编译器更清楚一个对象是否不再使用。 std::move 到处都是冗长的,降低了可读性。

最佳答案

一个对象在给定点之后不会被使用并不明显。例如,查看以下代码变体:

struct Bar {
~Bar() { std::cout << str.size() << std::endl; }
std::string& str;
}

Bar make_bar(std::string& str) {
return Bar{ str };
}

void foo (std::string str) {
// do sth. with str
}

int main() {
std::string a {"Test"};
Bar b = make_bar(a);
foo(std::move(a));
}

这段代码会中断,因为字符串 a 被 move 操作置于无效状态,但 Bar 持有对它的引用,并会在它被销毁时尝试使用它,这发生在 foo 调用之后。

如果 make_bar 定义在外部程序集(例如 DLL/so)中,编译器没有办法,在编译 Bar b = make_bar(a); 时,判断 b 是否持有对 a 的引用。因此,即使 foo(a)a 的最后一次使用,也不意味着使用 move 语义是安全的,因为其他一些对象可能持有引用a 作为 previous 指令的结果。

只有可以通过查看您调用的函数的规范来知道您是否可以使用 move 语义。

另一方面,您始终可以在 return 情况下使用 move 语义,因为该对象无论如何都会超出范围,这意味着任何持有对它的引用的对象都会导致未定义的行为无论 move 语义如何。顺便说一下,由于复制省略,您甚至不需要 move 语义。

关于c++ - 如果对象在下一步被破坏,为什么不自动 move ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29118538/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com