C++11 移动到本地 const 引用:作用域
C++11 move to local const reference: scope
对于常规的局部常量引用变量,作用域是prolonged。这就是以下代码按预期工作的原因:
#include <iostream>
#include <memory>
struct foo
{
foo()
{
std::cout << "foo() @" << (void*)this << std::endl;
}
~foo()
{
std::cout << "~foo() @" << (void*)this << std::endl;
}
};
int main()
{
auto const& f = std::make_shared<foo>();
std::cout << "f = " << f.get() << std::endl;
return 0;
}
// prints:
// foo() @0x55f249c58e80
// f = 0x55f249c58e80
// ~foo() @0x55f249c58e80
似乎在使用 std::move()
:
分配移动的对象时,这并没有像预期的那样工作
#include <iostream>
#include <memory>
#include <list>
struct foo
{
foo()
{
std::cout << "foo() @" << (void*)this << std::endl;
}
~foo()
{
std::cout << "~foo() @" << (void*)this << std::endl;
}
};
int main()
{
std::list<std::shared_ptr<foo>> l;
l.push_back(std::make_shared<foo>());
auto const& f = std::move(l.front());
l.clear();
std::cout << "f = " << f.get() << std::endl;
return 0;
}
// prints
// foo() @0x564edb58fe80
// ~foo() @0x564edb58fe80
// f = 0x564edb58fe80
std::move()
确实改变了范围,还是我在处理编译器错误?
将变量从 auto const& f
更改为 auto f
可以解决问题。如果我将移动包装到另一个函数中,它也有效:
auto const& f = [&]() { return std::move(l.front()); }();
这几乎就像 std::move()
不共享与函数调用相同的语义,而是好像它只是一个常规变量赋值:
auto const& f = std::move(l.front());
让我们搁置std::move()
并创建这个函数:
struct sometype {};
const sometype &foobar( const sometype &cref ) { return cref; }
现在我们使用它:
const sometype &ref = foobar( sometype() );
你怎么看,这种情况下临时文件的生命周期会延长吗?不,不会。仅当您直接 分配给引用时,生命周期才会延长。当它通过一个函数或通过 static_cast
或 std::move
时,延长就消失了。所以你和 std::move()
有完全相同的问题
struct sometype {
sometype() { std::cout << "ctype()" << std::endl; }
~sometype() { std::cout << "~ctype()" << std::endl; }
};
const sometype &foobar( const sometype &cref ) { return cref; }
int main()
{
const sometype &cref1 = foobar( sometype() );
sometype &&cref2 = std::move( sometype() );
std::cout << "main continues" << std::endl;
}
输出:
ctype()
~ctype()
ctype()
~ctype()
main continues
注意:你不应该在 return 语句中使用 std::move()
,它不会给你任何东西。
为了您的代码更改。您应该记住 std::move()
不会移动任何东西。它由特殊的赋值运算符或构造函数(如果它们提供了类型)完成。所以当你写这段代码时:
const type &ref = std::move( something );
不涉及构造函数和赋值运算符,因此不会发生移动。要进行实际移动,您必须将其分配给一个变量:
type val = std::move( something );
现在如果可能的话会搬家,否则就复制。
对于常规的局部常量引用变量,作用域是prolonged。这就是以下代码按预期工作的原因:
#include <iostream>
#include <memory>
struct foo
{
foo()
{
std::cout << "foo() @" << (void*)this << std::endl;
}
~foo()
{
std::cout << "~foo() @" << (void*)this << std::endl;
}
};
int main()
{
auto const& f = std::make_shared<foo>();
std::cout << "f = " << f.get() << std::endl;
return 0;
}
// prints:
// foo() @0x55f249c58e80
// f = 0x55f249c58e80
// ~foo() @0x55f249c58e80
似乎在使用 std::move()
:
#include <iostream>
#include <memory>
#include <list>
struct foo
{
foo()
{
std::cout << "foo() @" << (void*)this << std::endl;
}
~foo()
{
std::cout << "~foo() @" << (void*)this << std::endl;
}
};
int main()
{
std::list<std::shared_ptr<foo>> l;
l.push_back(std::make_shared<foo>());
auto const& f = std::move(l.front());
l.clear();
std::cout << "f = " << f.get() << std::endl;
return 0;
}
// prints
// foo() @0x564edb58fe80
// ~foo() @0x564edb58fe80
// f = 0x564edb58fe80
std::move()
确实改变了范围,还是我在处理编译器错误?
将变量从 auto const& f
更改为 auto f
可以解决问题。如果我将移动包装到另一个函数中,它也有效:
auto const& f = [&]() { return std::move(l.front()); }();
这几乎就像 std::move()
不共享与函数调用相同的语义,而是好像它只是一个常规变量赋值:
auto const& f = std::move(l.front());
让我们搁置std::move()
并创建这个函数:
struct sometype {};
const sometype &foobar( const sometype &cref ) { return cref; }
现在我们使用它:
const sometype &ref = foobar( sometype() );
你怎么看,这种情况下临时文件的生命周期会延长吗?不,不会。仅当您直接 分配给引用时,生命周期才会延长。当它通过一个函数或通过 static_cast
或 std::move
时,延长就消失了。所以你和 std::move()
struct sometype {
sometype() { std::cout << "ctype()" << std::endl; }
~sometype() { std::cout << "~ctype()" << std::endl; }
};
const sometype &foobar( const sometype &cref ) { return cref; }
int main()
{
const sometype &cref1 = foobar( sometype() );
sometype &&cref2 = std::move( sometype() );
std::cout << "main continues" << std::endl;
}
输出:
ctype()
~ctype()
ctype()
~ctype()
main continues
注意:你不应该在 return 语句中使用 std::move()
,它不会给你任何东西。
为了您的代码更改。您应该记住 std::move()
不会移动任何东西。它由特殊的赋值运算符或构造函数(如果它们提供了类型)完成。所以当你写这段代码时:
const type &ref = std::move( something );
不涉及构造函数和赋值运算符,因此不会发生移动。要进行实际移动,您必须将其分配给一个变量:
type val = std::move( something );
现在如果可能的话会搬家,否则就复制。