tags:

views:

234

answers:

7

is there any reason why

foo = (bar->at(x))->at(y);

works but

foo = bar[x][y];

does not work, where bar is a vector of vectors (using the c++ stl)

the declaration is:

std::vector< std::vector < Object * > * >

+4  A: 

Are you sure you have a vector of vectors? If you did then

foo = bar[x][y];

would be like

foo = bar.at(x).at(y);

but without the range checking and exception behaviour of at.

If bar->at(x)->at(y) works, then this is likely to be somewhat equivalent to (*(*bar)[x])[y] and not bar[x][y] but must mean that bar isn't a vector of vectors.

Charles Bailey
+1  A: 

Well, if bar is a pointer (as the first example suggests), you would need to rewrite your second example to:

(*(*foo)[x])[y]
R Samuel Klatchko
+1  A: 

if bar is a pointer, you'd want to dereference it first:

(*bar)[x][y]

if its a pointer to a vector of vector pointers:

(*(*bar)[x])[y]

as R Samuel Klatchko and others mentioned

jspcal
+8  A: 

Is it a vector of vectors or a vector of pointers to vectors? Your code should work as advertised:

typedef std::vector<int> vec_int;
typedef std::vector<vec_int> multi_int;

multi_int m(10, vec_int(10));

m.at(2).at(2) = /* ... */;
m[2][1] = /* ... */;

But your code appears to have:

typedef std::vector<vec_int*> multi_int; // pointer!
multi_int* m; // more pointer!

If you have pointers, you'll need to dereference them first to use operator[]:

(*(*m)[2])[2] = /* ... */;

That that can be ugly. Maybe use references temporarily:

multi_int& mr = m;
(*mr[2])[2] = /* ... */;

Though that still has some ugly. Maybe free-functions are helpful:

template <typename T>
typename T::value_type& access_ptr(T* pContainer,
                                    unsigned pInner, unsigned pOuter)
{
    return (*(*pContainer)[pInner])[pOuter]);
}

access_ptr(m, 2, 2) = /* ... */

Most preferable is to be rid of the pointers, though. Pointers can leak and have all sorts of problems, like leaking when exceptions are thrown. If you must use pointers, use a pointer container from boost for the inner vector, and store the actual object in a smart pointer.

Also, your title is a bit misleading. The difference between at and operator[] is that at does range checks. Otherwise, they are the same.

GMan
I assumed `bar`was a `std::vector<std::vector<T> >*`, hence the `->at()`
jalf
It would need to be `std::vector<std::vector<T>* >*`, there are two `->` .
Charles Bailey
Oops, didn't see that.
GMan
Oops yeah, I didn't see the other one. Charles is right, of course
jalf
+1  A: 

Depends on how you define "works" and "doesn't work". What happens when it "doesn't work"? The main difference between the two is that at performs bounds-checking, which operator[] does not.

But in your case, the problem is that bar is not a vector of vectors. It seems to be a pointer to a vector of pointers to vectors. (Which in itself is a bad sign. It probably doesn't need to be a pointer. Is everything also dynamically allocated with new? Don't do that by default)

And that means that you're trying to invoke operator[] on a pointer, not a vector -- which is defined, but does something other than you expect. The code in your second case is effectively equivalent to (*(bar+x))[y] - and apart from going out of bounds yielding undefined behavior, the result would be a pointer to a vector of whatever type foo is, rather than an element of that vector.

jalf
+1  A: 

It would seem you have a pointer to a vector of pointers to vectors ...

So if you want to do as you've tried you'd need

foo = (*((*bar)[x]))[Y];

Use a vector of vectors (ie std::vector< std::vector< datatype > > instead.

Edit: Also worth noting that at does do some range checks so, provided you don't need those range checks, is slower than using operator[].

Goz
A: 

For

foo = (bar->at(x))->at(y);

to work bar would have to be a pointer and the vector it points to would have to contain pointers.

For

foo = bar[x][y];

to work, bar would have to be a vector (not a pointer) that contained vectors (not pointers).

Michael Burr