0

I have a 2 dimensional structure of objects initialized as thus:

std::vector<std::shared_ptr<tile> > appearance;
for (int x = 0; x < building_data.x_width; x++)
    {
            appearance.push_back
            (std::shared_ptr<tile>(new tile[building_data.y_length]));
    }

now, as far as I can figure out, the only way to access a member function of a tile in this is to use

appearance.at(x).get()[y].member_function()

which is confusing and cumbersome, and I feel like I'm missing something.

Previously, I had used tile** for the same structure, and the syntax of tile[x][y] was nice but the raw pointers were a headache.

So, is there a better way access functions of an object held in an array, where the first element in the array is pointed to by a smart pointer held in a vector? Wordy but its the best I have.

destrovel
  • 75
  • 1
  • 10

3 Answers3

1

You can use the -> operator to access members of the object managed by the shared_ptr. It's the same syntax you use with raw pointers.

However, you're going to run into problems with delete as mentioned in Dantez's answer.

Also, it looks like you're building some sort of board of tiles, perhaps for a game? Have you considered replacing the multidimensional array with with a 1D vector and some accessor functions?

// board_width and height should be integers
std::vector<Tile> board;
board.reserve(board_width * board_height);
for (unsigned y_axis = 0; y_axis < board_height; ++y_axis)
{
    for (unsigned x_axis = 0; x_axis < board_width; ++x_axis)
    {
        board.push_back(Tile());
    }
}

...

vec2 index_to_coords(unsigned index)
{
    return vec2(index % board_width, index / board_width);
}

...

unsigned coords_to_index(const vec2& coords)
{
    return (static_cast<unsigned>(coords.y) * board_width) + static_cast<unsigned>(coords.x);
}
Fibbs
  • 1,350
  • 1
  • 13
  • 23
0

First of all, shared_ptr is not designed to work with arrays. When there is no more references, it calls delete instead of delete[] which results in undefined behaviour if managed object is an array. You can read about it here.

As for accessing shared_ptr object, you can use operator* to dereference it.

Also, if you know vector's final size, you may want to reserve some space to avoid reallocation.

Community
  • 1
  • 1
  • While I'm not arguing against your point, it's true that shared_ptr from TR1 was not so equipped, the current C++11/C++14 std::shared_ptr has a provision for it (a customer deleter), it just takes an extra bit of effort. – JVene Sep 24 '15 at 00:11
  • @JVene You can find it in the link I provided. –  Sep 24 '15 at 07:53
0

I agree with Fibbles, but have an alternate idea to provide. Fibble's approach is actually quite common even in C, because multidimensional structures (matrices) are just much easier that way.

However, if you do insist on the two dimensional concept, you can nest vectors. Consider:

typedef std::vector< tile >     TileRow;
typedef std::vector< TileRow >  Tiles;

At first, this may be a bit confusing, so to be clear that creates:

std::vector< std::vector< tile > > t;

However, with the typedef, thats

Tiles t;

Now, that's empty. To use it you'd need to push in some rows, and for each row push in some columns. You might not like that, so...you can use the assign function to set some rows. If, for example, you needed a matrix of 10 rows by 10 columns, you might

t.assign( 10, TileRow( 10, tile() ) ); 

This assume tile has a default constructor, pushing 10 rows of TileRow, each with 10 columns of default constructed tiles.

Now, t[ 1 ] returns a reference to the row 1. As such, t[ 1 ][ 1 ] is a reference to the tile at location 1,1, much like an array.

Yet, now you have no allocation/deallocation issues.

Something similar can be done with std::array, even better.

typedef std::array< tile, 10 >     TileRow;
typedef std::array< TileRow, 10 >  Tiles;

Tiles t;

At which point, t is ready with default initialized tiles.

JVene
  • 1,611
  • 10
  • 10