这是正确使用C ++的“移动”语义吗? [英] Is this correct usage of C++ 'move' semantics?

查看:111
本文介绍了这是正确使用C ++的“移动”语义吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今晚我一直在看看我在过去几天一直在做的一些代码,并开始阅读移动语义,特别是std :: move。我有几个问题要问你的专业人员,以确保我走正确的道路,不做任何愚蠢的假设!



首先:



1)最初,我的代码有一个返回大型向量的函数:

  template< class T> class MyObject 
{
public:
std :: vector< T> doSomething()const;
{
std :: vector< T> theVector;

//生成/使用向量

return(theVector);
}; // eo doSomething
}; // eo class MyObject

给定theVector是临时的,将函数修改为:

  std :: vector< T& doSomething()const; 
{
std :: vector< T> theVector;

//在这里产生/使用向量

return(static_cast< std :: vector< T>&&>(theVector)
}; // eo doSomething

这样是否正确?



2)我注意到在一个函数中,我返回 std :: string 它自动调用move构造函数。调试到返回的字符串(thankyou,阿拉贡),我注意到它称为显式移动构造函数。为什么有一个字符串类和不向量?



我不必对此函数进行任何修改以利用移动语义:

  //下面,不需要std :: string&&返回值? 
std :: string AnyConverter :: toString(const boost :: any& _val)const
{
string ret;
// convert here
return(ret); //不需要static_cast< std :: string&&> ?
}; // eo toString

3)最后,我想做一些性能测试,



(<$ c的实现方式) $ c> _getMilliseconds()为简洁起见省略)

  std :: vector< int& v; 
for(int a(0); a< 1000000; ++ a)
v.push_back(a);

std :: vector< int> X;
for(int a(0); a< 1000000; ++ a)
x.push_back(a);

int s1 = _getMilliseconds()?
std :: vector< int> v2 = v;
int s2 = _getMilliseconds();
std :: vector< int> v3 = std :: move(x);
int s3 = _getMilliseconds();

int result1 = s2 - s1;
int result2 = s3 - s2;

结果是,显然,真棒。 result1,标准赋值,花费630ms。第二个结果,是0ms。这是一个良好的性能测试这些东西吗?



我知道一些这是很明显的很多你,但我想确保我理解的语义

提前感谢!

解决方案

引用仍然是引用。以同样的方式,你不能返回一个本地的引用在C ++ 03(或你得到UB),你不能在C ++ 0x。你最终会得到一个死对象的引用;它恰好是一个右值引用。所以这是错误的:

  std :: vector< T& doSomething()const 
{
std :: vector< T>本地;

返回local; // oops
return std :: move(local); //也oops
}

你应该做你在第二个看到的: / p>

  //好的,返回值
std :: vector< T& doSomething()const
{
std :: vector< T>本地;

return local; //完全相同:
return std :: move(local); // move-construct value
}

,因此不需要更改任何代码。



你想使用 std :: move 显示移动东西,当它不能正常进行,像在你的测试。 (这看起来很好;是在Release中你应该输出向量的内容,否则编译器会优化它。)



如果你想学习关于右值引用,阅读此


Tonight I've been taking a look at some code I've been working on over the last few days, and began reading up on move semantics, specifically std::move. I have a few questions to ask you pros to ensure that I am going down the right path and not making any stupid assumptions!

Firstly:

1) Originally, my code had a function that returned a large vector:

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

Given "theVector" is temporary in this and "throw-away", I modified the function to:

    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

Is this correct? Any pitfalls in doing it this way?

2) I noticed in a function I have that returns std::string that it automatically called the move constructor. Debugging in to Return of the String (thankyou, Aragorn), I noticed it called an explicit move constructor. Why is there one for the string class and not vector?

I didn't have to make any modifications to this function to take advantage of move semantics:

// below, no need for std::string&& return value?
std::string AnyConverter::toString(const boost::any& _val) const
{
    string ret;
    // convert here
    return(ret); // No need for static_cast<std::string&&> ?
}; // eo toString

3) Finally, I wanted to do some performance tests, is the amazingly-fast results I got because of std::move semantics or did my compiler (VS2010) do some optimizing too?

(Implementation of _getMilliseconds() omitted for brevity)

std::vector<int> v;
for(int a(0); a < 1000000; ++a)
    v.push_back(a);

std::vector<int> x;
for(int a(0); a < 1000000; ++a)
    x.push_back(a);

    int s1 = _getMilliseconds();
std::vector<int> v2 = v;
    int s2 =  _getMilliseconds();
std::vector<int> v3 = std::move(x);
    int s3 =  _getMilliseconds();

    int result1 = s2 - s1;
    int result2 = s3 - s2;

The results were, obviously, awesome. result1, a standard assignment, took 630ms. The second result, was 0ms. Is this a good performance test of these things?

I know some of this is obvious to a lot of you, but I want to make sure I understand the semantics right before I go blazer on my code.

Thanks in advance!

解决方案

A reference is still a reference. In the same way you cannot return a reference to a local in C++03 (or you get UB), you can't in C++0x. You'll end up with a reference to a dead object; it just happens to be an rvalue reference. So this is wrong:

std::vector<T>&& doSomething() const
{
    std::vector<T> local;

    return local; // oops
    return std::move(local); // also oops
}

You should just do what you saw in number two:

// okay, return by-value 
std::vector<T> doSomething() const
{
    std::vector<T> local;

    return local; // exactly the same as:
    return std::move(local); // move-construct value
}

Variables local to a function are temporary when you return, so there's no need to change any of your code. The return type is the thing responsible for implementing move semantics, not you.

You want to use std::move to explicitly move something, when it wouldn't be done normally, like in your test. (Which seems to be fine; was that in Release? You should output the contents of the vector, or the compiler will optimize it away.)

If you want to learn about rvalue references, read this.

这篇关于这是正确使用C ++的“移动”语义吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆