我不明白何时应该使用std::move,何时应该让编译器优化...例如:
using SerialBuffer = vector< unsigned char >;
// let compiler optimize it
SerialBuffer read( size_t size ) const
{
SerialBuffer buffer( size );
read( begin( buffer ), end( buffer ) );
// Return Value Optimization
return buffer;
}
// explicit move
SerialBuffer read( size_t size ) const
{
SerialBuffer buffer( size );
read( begin( buffer ), end( buffer ) );
return move( buffer );
}
Run Code Online (Sandbox Code Playgroud)
我应该使用哪个?
由于范围问题,我对此感到疑惑.例如,考虑代码
typedef struct {
int x1;/*top*/
int x2;/*bottom*/
int id;
} subline_t;
subline_t subline(int x1, int x2, int id) {
subline_t t = { x1, x2, id };
return t;
}
int main(){
subline_t line = subline(0,0,0); //is line garbage or isn't it? the reference
//to subline_t t goes out of scope, so the only way this wouldn't be garbage
//is if return copies
}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,返回语句是否总是复制?在这种情况下,它似乎工作,所以我被引导相信返回确实复制.如果它复制了,它会在每种情况下复制吗?
RVO(返回值优化)是否保证适用于C++编译器(特别是GCC)中的所有对象和情境?
如果答案是"否",那么对类/对象进行优化的条件是什么?如何强制或鼓励编译器对特定的返回值执行RVO?
我在C++中有一个非常基本的问题.返回对象时如何避免复制?
这是一个例子:
std::vector<unsigned int> test(const unsigned int n)
{
std::vector<unsigned int> x;
for (unsigned int i = 0; i < n; ++i) {
x.push_back(i);
}
return x;
}
Run Code Online (Sandbox Code Playgroud)
据我了解C++是如何工作的,这个函数将创建2个向量:本地一个(x),以及将返回的x的副本.有没有办法避免副本?(我不想返回指向对象的指针,但是对象本身)
使用"移动语义"(在评论中说明)该函数的语法是什么?
今晚我一直在看一些我过去几天一直在研究的代码,并开始阅读移动语义,特别是std :: move.我有几个问题要求专业人士确保我走正确的道路而不做任何愚蠢的假设!
首先:
1)最初,我的代码有一个返回大向量的函数:
template<class T> class MyObject
{
public:
std::vector<T> doSomething() const;
{
std::vector<T> theVector;
// produce/work with a vector right here
return(theVector);
}; // eo doSomething
}; // eo class MyObject
Run Code Online (Sandbox Code Playgroud)
鉴于"theVector"在这个和"扔掉"中是暂时的,我将该函数修改为:
std::vector<T>&& doSomething() const;
{
std::vector<T> theVector;
// produce/work with a vector right here
return(static_cast<std::vector<T>&&>(theVector));
}; // eo doSomething
Run Code Online (Sandbox Code Playgroud)
它是否正确?这样做有什么陷阱吗?
2)我在一个函数中注意到它返回std::string它自动调用移动构造函数.调试返回字符串(thankyou,Aragorn),我注意到它称为显式移动构造函数.为什么有一个字符串类而不是矢量?
我没有必要对此函数进行任何修改以利用移动语义:
// below, no need for std::string&& return value?
std::string AnyConverter::toString(const boost::any& _val) const
{
string ret;
// convert here
return(ret); // No …Run Code Online (Sandbox Code Playgroud) 据我所知,添加移动语义的目的之一是通过调用特殊构造函数来复制"临时"对象来优化代码.例如,在这个答案中我们看到它可以用来优化这些string a = x + y东西.因为x + y是一个rvalue表达式,所以我们只能复制指向字符串的指针和字符串的大小,而不是深度复制.但正如我们所知,现代编译器支持返回值优化,因此不使用移动语义,我们的代码根本不会调用复制构造函数.
为了证明这一点,我写了这段代码:
#include <iostream>
struct stuff
{
int x;
stuff(int x_):x(x_){}
stuff(const stuff & g):x(g.x)
{
std::cout<<"copy"<<std::endl;
}
};
stuff operator+(const stuff& lhs,const stuff& rhs)
{
stuff g(lhs.x+rhs.x);
return g;
}
int main()
{
stuff a(5),b(7);
stuff c = a+b;
}
Run Code Online (Sandbox Code Playgroud)
在VC++ 2010中执行它并在优化模式下执行g ++后,我得到空输出.
它是什么样的优化,如果没有它,我的代码仍然可以更快地运行?你能解释一下我的理解错误吗?
在"C++ Concurrency in Action"一书中阅读以下方法
std::unique_lock<std::mutex> wait_for_data()
{
std::unique_lock<std::mutex> head_lock(head_mutex);
data_cond.wait(head_lock,[&]{return head.get()!=get_tail();});
return std::move(head_lock);
}
Run Code Online (Sandbox Code Playgroud)
我无法理解为什么返回时head_lock是std :: move-ed.我对移动用法和RVO的观念和直觉与C++ 11 rvalues中共享的观点相匹配,并且移动了语义混淆(return语句)
但我倾向于相信作者更了解.有人可以澄清什么时候std :: move返回值更好,是否有关于锁的具体内容?谢谢.
可能重复:
C++ 11 rvalues并且移动语义混乱
我认为是正确的
std::string GetLine()
{
std::string str;
std::getline(std::cin, str);
return std::move(str);
}
Run Code Online (Sandbox Code Playgroud)
但是在这个链接http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html (检查标题部分返回一个明确的右值引用功能)
这是#1谷歌搜索命中移动语义显示类似的功能签名
int&& GetInt()
{
int x = 0;
// code here
return std::move(x);
}
Run Code Online (Sandbox Code Playgroud)
从我在其他地方读到的&&表示右值引用,所以在这种情况下它返回对不存在的对象的引用.
那是哪个呢?
(是的,我知道移动一个int没有真正的好处,但问题是在第一个函数中是否使用std :: string或std :: string &&的返回类型.如果这是应该对所有类型执行的方式.)
考虑从函数返回启用了移动语义的"整个"对象的情况,如std::basic_string<>:
std::wstring build_report() const
{
std::wstring report;
...
return report;
}
Run Code Online (Sandbox Code Playgroud)
然后我可以真实地期望做出"最佳"选择是否使用带有移动语义的返回字符串,如
const std::wstring report(std::move(build_report()));
Run Code Online (Sandbox Code Playgroud)
或者我是否应该依赖(N)RVO来进行
const std::wstring report(build_report());
Run Code Online (Sandbox Code Playgroud)
甚至将const引用绑定到临时用
const std::wstring& report(build_report());
Run Code Online (Sandbox Code Playgroud)
有什么方案可以确定性地选择这些选项,如果有的话?
编辑1:请注意,std::wstring上面的用法只是移动语义启用类型的一个示例.它也可以换成你的arbitrary_large_structure.:-)
编辑2:我在VS 2010中运行以下速度优化版本时检查生成的程序集:
std::wstring build_report(const std::wstring& title, const std::wstring& content)
{
std::wstring report;
report.append(title);
report.append(content);
return report;
}
const std::wstring title1(L"title1");
const std::wstring content1(L"content1");
const std::wstring title2(L"title2");
const std::wstring content2(L"content2");
const std::wstring title3(L"title3");
const std::wstring content3(L"content3");
int _tmain(int argc, _TCHAR* argv[])
{
const std::wstring report1(std::move(build_report(title1, content1)));
const std::wstring …Run Code Online (Sandbox Code Playgroud) 按照这个答案给出的建议,我+在我的简单Point类中重载了运算符如下(+ =重载工作正常).
Point operator+ (Point p1, const Point& p2)
{
return std::move(p1 += p2);
}
Run Code Online (Sandbox Code Playgroud)
但我得到一个错误说
重载'operator +'必须是一元或二元运算符(有3个参数)
怎么了?