英文:
std::move and static_cast<&&>
问题
当我调用std::move()
与一个临时对象,比如std::move(A())
或std::move(int)
,它会返回一个指向自由内存的引用吗?
据我所知,如果T&&
或const T&&
分配给一个rvalue或prvalue,它会在内存中创建一个对象,并在引用未被销毁时继续对象的生命周期。第二次对引用的分配是否会延续对象的生命周期?
另外,如果我调用,例如:int x; static_cast<int&&>(x)
,据我所知这是一个xvalue表达式(引用),但对象的生命周期会发生什么变化?
int&& foo() {
int n = 5;
return std::move(n);
}
foo(); // 第二个rvalue引用能够在仍有引用指向对象时延续对象的生命周期吗?
int x = 0;
static_cast<int&&>(x); // 对象的生命周期会发生什么变化?或者
static_cast<const int&>(x);
std::move(0); // 它会返回自由内存吗?或者
std::move(std::string("hello, world!"));
我只是一个初学者,如果我犯了任何错误,我会很感激你的纠正。
英文:
Do I understand right, if I call std::move()
with a temporary object, like std::move(A())
or std::move(int)
, it returns a reference to free memory?
As I know, if T&&
or const T&
assigns to rvalue or prvalue, it creates an object in memory and continues the life-time of the object while the reference is not destroyed? Does a second assign to a reference continue the life-time of the object?
Also, if I call, for example: int x; static_cast<int&&>(x)
, as I know it is an xvalue statement (reference), but what happens with the life-time of the object?
int&& foo() {
int n = 5;
return std::move(n);
}
foo(); // can second rvalue reference continue life of object while exist ref to object?
int x = 0;
static_cast<int&&>(x); // what happens with life time of object? or
static_cast<const int&>(x);
std::move(0); // will it return free memory? or
std::move(std::string("hello, world!"));
I'm just a beginner, and I would appreciate it if you could correct me if I make any mistakes.
答案1
得分: 3
对象的生命周期在创建时确定,之后永远不会改变。对于已经存在的对象,无法采取任何操作来改变其生命周期。
对于你的具体示例:
int&& foo() {
int n = 5;
return std::move(n);
}
foo
返回一个悬空引用。n
的生命周期在 foo
返回时结束。由于 foo
返回对 n
的引用,而 n
的生命周期已经结束,对由 foo
返回的引用进行任何读取或写入操作都将导致未定义行为。
int x = 0;
static_cast<int&&>(x);
static_cast<const int&>(x);
这些转换不起作用。即使结果被赋给另一个变量,它们也不会影响 x
的生命周期。
std::move(0);
std::move(std::string("hello, world!"));
这两个都返回悬空引用。0
和 std::string("hello, world!")
都创建临时对象。引用生命周期延长会将它们的生命周期延长到 std::move
的参数的生命周期(因为它们在创建时立即绑定到该引用),但该参数的生命周期仍然短于临时对象的生命周期。
你的一些困惑似乎来自 C++ 的所谓 "引用生命周期延长" 特性。然而,这并不会延长现有对象的生命周期。它只能延长对象在创建时的生命周期。
如果临时对象在创建时立即绑定到引用,那么临时对象的生命周期将延长到引用的生命周期。
也就是说,引用生命周期延长适用于以下所有情况:
// 在此,字符串字面量 "Hello World" 被转换为临时 std::string
// 临时对象的生命周期延长到 foo 的生命周期
const std::string& foo = "Hello World";
// 在这里,func 的返回值是一个临时 int 对象
// 临时对象的生命周期延长到 i 的生命周期
int func() { return 42; }
const int& i = func();
引用生命周期延长不适用于这些情况:
// 由 int 字面量 42 创建的临时对象不会
// 生命周期延长到 i,因为它在创建时没有绑定到 i
const int& func() { return 42; }
const int& i = func();
// 由字符串字面量 "some string" 创建的临时 std::string 对象的生命周期
// 不会延长到 f.member_ref,因为它在创建时没有绑定到 member_ref
struct Foo
{
const std::string& member_ref;
Foo(const std::string& s) : member_ref(s) {}
};
Foo f("some string");
英文:
The lifetime of an object is determined when the object is created and never changes after that. There is nothing you can do to an already-existing object that will cause its lifetime to change.
For your specific examples:
int&& foo() {
int n = 5;
return std::move(n);
}
foo
returns a dangling reference. The lifetime of n
ends when foo
returns. Since foo
returns a reference to n
, and n
's lifetime has ended, any read or write to the reference returned by foo
will result in undefined behavior.
int x = 0;
static_cast<int&&>(x);
static_cast<const int&>(x);
These casts do nothing. Even if the result was assigned to another variable, they would have no effect on the lifetime of x
.
std::move(0);
std::move(std::string("hello, world!"));
These both return dangling references. 0
and std::string("hello, world!")
both create temporary objects. Reference lifetime extension would extend their lifetimes to the lifetimes of std::move
's argument (since they are bound to that reference immediately at the moment they're created), but that argument's lifetime is shorter than that of the temporary objects anyway.
Some of your confusion seems to come from the so-called "reference lifetime extension" feature of C++. This does not, however, extend the lifetime of existing objects. It can only extend the lifetime of an object as it is being created.
If a temporary object is bound to a reference immediately upon creation then that temporary object's lifetime is extended to the lifetime of the reference.
That is, reference lifetime extension applies in all of the following cases:
// Here the string literal "Hello World" is converted to a to a temporary std::string
// which has its lifetime extended to the lifetime of foo
const std::string& foo = "Hello World";
// Here the return value of func is a temporary int object
// which has its lifetime extended to that of i
int func() { return 42; }
const int& i = func();
Reference lifetime extension does not apply in these situations:
// The temporary object created by the int literal 42 does not have
// its lifetime extended to that of i because it is not bound to i
// at the moment of its creation.
const int& func() { return 42; }
const int& i = func();
// The lifetime of the temporary std::string object created from the
// string literal "some string" does not get extended to the lifetime
// of f.member_ref because it is not bound to member_ref at the moment
// of its creation
struct Foo
{
const std::string& member_ref;
Foo(const std::string& s) : member_ref(s) {}
};
Foo f("some string");
</details>
# 答案2
**得分**: 1
我认为混淆是因为```std::move()```不移动任何东西。它只是一种类型转换。它完全不参与内存管理。
如果你有一个函数利用其参数是右值引用的事实来执行本应不安全的操作(比如使参数无效),编译器将保护你免受使用左值调用这样的函数。然而,如果你想使用左值调用这样的函数,知道你的变量可能会失效,```std::move()```会将其转换为右值,以便你可以调用该函数。
然而,可能使参数无效的是函数本身,而不是```std::move```。```std::move```只是使调用这样一个函数成为可能。
<details>
<summary>英文:</summary>
I think the confusion is because ```std::move()``` doesn't move anything. It is only a typecast. It doesn't participate in memory management at all.
If you have a function that takes advantage of the fact that its argument is an rvalue reference to do what would otherwise be unsafe (like invalidating the argument), the compiler will protect you from calling such a function with an lvalue. If, however, you *want* to call such a function with an lvalue, knowing that your variable may be invalidated, ```std::move()``` casts it to an rvalue so you can call the function.
It's the function, however, not the ```std::move```, that potentially the invalidates the argument. The ```std::move``` just makes it possible to call such a function.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论