vendredi 29 avril 2016

Move semantic for thrust::device_vector

I am trying to simplify some code that make improper use of std::shared_ptr for handling objects returned by methods.

To do so, I want to rely on std::move, but I am afraid of the fact that thrust does not seem to handle the move construction properly. I wrote a small piece of code that intend to demonstrate this fact.

Could you tell me if the return value of this code is the one that we should expect from a proper implementation of move construction in thrust::device_vector ?

#include <thrust/device_vector.h>
#include <thrust/fill.h>

#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
#include <utility>
#include <algorithm>

class Foo
{
public:
    Foo() : m_v(1,5555)
    {
        std::cout <<"This is the normal constructor with addr "<<
        thrust::raw_pointer_cast( m_v.data() )<<std::endl;
    }
    virtual ~Foo()=default;

    //Copy constructor
    Foo( const Foo& other) : m_v(other.m_v)
    {
        std::cout <<"This is the copy constructor with addr "<<
        thrust::raw_pointer_cast( m_v.data() )<<std::endl;
    }
    //Move constructor
    Foo( Foo&& other) : m_v(std::move(other.m_v))
    {
        std::cout <<"This is the move constructor with addr "<<
        thrust::raw_pointer_cast( m_v.data() )<<std::endl;
    }
    //Move assignment
    Foo& operator=(Foo&& other)
    {
        m_v = std::move(other.m_v);
        std::cout <<"This is the move assignment operator with addr "<<
            thrust::raw_pointer_cast( m_v.data() )<<std::endl;
        return *this;
    }
    //Assignment operator
    Foo& operator=(const Foo& other)
    {
        m_v = other.m_v;
        std::cout <<"This is the assignment operator with addr "<<
        thrust::raw_pointer_cast( m_v.data() )<<std::endl;
            return *this;
    }
    void fillWithVal( int val )
    {
        thrust::fill(m_v.begin(), m_v.end(), val);
    }
    void printValue() const
    {
        std::for_each(m_v.cbegin(), m_v.cend(), [](int in){std::cout<<in<<std::endl;});
    }
protected:
    thrust::device_vector<int> m_v;
};

Foo GetFoo()
{
    Foo f;
    f.fillWithVal( 255 );
    return std::move(f);
}

//Compile using nvcc -std=c++11 ./main.cu -o ./test
//eventually with -fno-elide-constructors
int main()
{
    std::cout <<"test 0 "<<std::endl;
    Foo f = GetFoo();
    f.printValue();

    return EXIT_SUCCESS;
}

The return value is:

test 0 
This is the normal constructor with addr 0xd06c00000
This is the move constructor with addr 0xd06c00200
255

Why do I get two different addresses ? It looks like there is a new allocation of device_vector, and that the pointer to the raw data is not the same anymore.

I tested a very similar code of pure c++11 host code that make use of std::vector (not shown here) and I got the same value printed out for the raw pointer.

Thank you in advance for your help

Aucun commentaire:

Enregistrer un commentaire