Transferring ownership of objects

I'm fairly new to RAII, and I have a class (let's call it A) which contains an std::array which has four std::shared_ptrs to four objects of another user defined class (let's call it B). What I want to do is with a function call, transfer ownership of the four Bs, into a vector that is passes into the function, so that they A can be reset to have four new Bs. My problem is how to do this without destroying any of the Bs.
I don't understand what you want to do exactly but I think you want to move them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class B { ... };

class A {
public:
    // 1st: transfer ownership between A-objects
    void transfer_to(A& other) {
        other.ptrs = std::move(this.ptrs); // move assignment operator is invoked.
    }
    // 2nd: transfer ownership to outside of the function
    std::array<std::shared_ptr<B>, 4> get_ownership() { 
        return std::array<std::shared_ptr<B>, 4>(std::move(ptr));
    }

private:
    std::array<std::shared_ptr<B>, 4> ptrs;
};
Last edited on
This sounds like a rather ugly design. What are you trying to accomplish, exactly?
I'm making tetris. I have a class for each block, and a class for each tetrimino that just carries four blocks down until they land and deals with rotation and stuff like that. What I have to do is transfer the blocks from the tetrimino to the pile of blocks at the bottom, which then frees up the tetrimino so it can be given four new blocks and go back to the top again so it can make them fall down etc
EDIT: Would it work if my array of blocks in the pile at the bottom is initially reset and then the correct member of that array and the shared_ptr in the tetrimino class are swapped with std::swap()?
Last edited on
Transfer of ownership is mandatory only with std::unique_ptr<>

With std::shared_ptr<>, we could just copy into the vector and then overwrite the original with a new value.

Move transfers ownership, and would work with both unique and shared pointers. For instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <memory>
#include <array>
#include <vector>
#include <iterator>

struct block
{
    virtual ~block() = default ;
    // ...
    const int block_number = ++slno ;
    static int slno ;
};

int block::slno = 0 ;

struct tetrimino
{
    // transfer of ownership is required for std::unique_ptr<block>
    std::array< std::unique_ptr<block>, 4 > blocks ;

    tetrimino() { new_blocks() ; }

    // give it four new blocks
    void new_blocks()
    {
        // note: std::make_unique<> requires C++14
        // http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique
        // with C++11, ptr = std::unique_ptr<block>( new block( /* ... */ ) ) ;
        for( auto& ptr : blocks ) ptr = std::make_unique<block>( /* ... */ ) ;
    }

    void cycle_blocks( std::vector< std::unique_ptr<block> >& pile )
    {
        // transfer ownership of the blocks to pile (move the smart pointers into the pile)
        // see: http://en.cppreference.com/w/cpp/iterator/move_iterator
        // http://en.cppreference.com/w/cpp/iterator/make_move_iterator
        pile.insert( std::end(pile),
                     std::make_move_iterator( std::begin(blocks) ),
                     std::make_move_iterator( std::end(blocks) ) ) ;

        print( std::cout << "after move, " ) << '\n' ;

        new_blocks() ; // give it four new blocks
        print( std::cout << "after new_blocks(), " ) << '\n' ;
    }

    std::ostream& print( std::ostream& stm ) const
    {
        stm << "tetrimino holds blocks: " ;
        for( const auto& ptr : blocks )
            if(ptr) stm << ptr->block_number << ' ' ;
            else stm << "nil " ;
        return stm ;
    }
};

std::ostream& operator<< ( std::ostream& stm, const tetrimino& tet ) { return tet.print(stm) ; }

int main()
{
    tetrimino tet ;
    std::cout << tet << '\n' ;
    std::vector< std::unique_ptr<block> > pile ;

    for( int i = 0 ; i < 3 ; ++i )
    {
        tet.cycle_blocks(pile) ;

        std::cout << "pile now holds blocks: " ;
        for( const auto& ptr : pile ) std::cout << ptr->block_number << ' ' ;
        std::cout << "\n---------------------------\n" ;
    }
}

http://coliru.stacked-crooked.com/a/80021ed334585e43
Thanks for the extensive replay. I think I understand it now.
This
1
2
3
        pile.insert( std::end(pile),
                     std::make_move_iterator( std::begin(blocks) ),
                     std::make_move_iterator( std::end(blocks) ) ) ;

is needlessly over-elaborate.


std::move() (<algorithm>) yields code that is far more readable. http://en.cppreference.com/w/cpp/algorithm/move

std::move( std::begin(blocks), std::end(blocks), std::back_inserter(pile) ) ;

http://coliru.stacked-crooked.com/a/58f898491b1167ba
Topic archived. No new replies allowed.