Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

More concise syntax for addressing std::vector* ???

1 view
Skip to first unread message

Peter Olcott

unread,
Mar 20, 2009, 11:33:42 PM3/20/09
to
double Num = 987654321.987654;
std::vector<double> Test;
std::vector<double>* Ptr;
Ptr = &Test;
Test.push_back(Num);
printf("%f\n", Test[0]);
printf("%f\n", Ptr->operator[](0) );

Is there a more concise way of saying this:
Ptr->operator[](0)


Balog Pal

unread,
Mar 20, 2009, 11:38:40 PM3/20/09
to
"Peter Olcott" <NoS...@SeeScreen.com>

> Is there a more concise way of saying this:
> Ptr->operator[](0)
(*Ptr)[0];


Peter Olcott

unread,
Mar 21, 2009, 9:03:26 AM3/21/09
to
"Balog Pal" <pa...@lib.hu> wrote in message
news:gq1nc6$1nhk$1...@news.ett.com.ua...

That worked in this simple case. What about this more
complex case:

Number03 = Array01.Array->operator[](0).

Array->operator[](0).

Array->operator[](0).

Array->operator[](0).

Array->operator[](0).

Array->operator[](0).Number;


Balog Pal

unread,
Mar 21, 2009, 10:08:49 AM3/21/09
to
"Peter Olcott" <NoS...@SeeScreen.com>

>> (*Ptr)[0];
>
> That worked in this simple case. What about this more complex case:

>
> Number03 = Array01.Array->operator[](0).
>
> Array->operator[](0).
>
> Array->operator[](0).
>
> Array->operator[](0).
>
> Array->operator[](0).
>
> Array->operator[](0).Number;

This looks more like an abomination than case, do you think it;s readable
despite the syntax?
But if you actually want it like that, just use at() instead of [], if
'Array' is a vector<>*.
With your original example this would not compile would it?
And with your own type you create the sensible syntax.

= Array->at(0).Array->at(0).Array->at(0).Array->at(0).Array->at(0).number;

hmmm.


Juha Nieminen

unread,
Mar 21, 2009, 10:54:50 AM3/21/09
to
Balog Pal wrote:
> But if you actually want it like that, just use at() instead of []

As a bonus, you'll get boundary checks. (May be just slightly slower,
but that's often irrelevant unless you need to index the vector millions
of times per second.)

litb

unread,
Mar 21, 2009, 11:13:31 AM3/21/09
to
On 21 Mrz., 14:03, "Peter Olcott" <NoS...@SeeScreen.com> wrote:
> "Balog Pal" <p...@lib.hu> wrote in message

> That worked in this simple case. What about this more
> complex case:
>
> Number03 = Array01.Array->operator[](0).
>
>                    Array->operator[](0).
>
>                    Array->operator[](0).
>
>                    Array->operator[](0).
>
>                    Array->operator[](0).
>
>                    Array->operator[](0).Number;

There is still this way:

= Array03.Array[0][0].Array[0][0].Array[0][0].Array[0][0].Array[0]
[0].Array[0][0].Number;

Vaclav Haisman

unread,
Mar 21, 2009, 11:38:09 AM3/21/09
to
Such deep array structures are highly unlikely. If you do not like
(*vecptr)[0] then use reference: std::vector<foo> & v = *vecptr; v[0];.

--
VH

Peter Olcott

unread,
Mar 21, 2009, 9:44:04 PM3/21/09
to

"Vaclav Haisman" <v.ha...@sh.cvut.cz> wrote in message
news:49C509E1...@sh.cvut.cz...

It is a given (like in geometry, it can't change) design
requirement that the depth of reference specified above can
not be changed. I don't want to explain my reasoning because
that would require disclosing proprietary information.

The above syntax compiles and produce the desired
functionality. I just want to be able to specify it more
concisely if possible.


Peter Olcott

unread,
Mar 21, 2009, 9:54:29 PM3/21/09
to
That looks like it works, could you please explain why it
works?

"litb" <lit...@googlemail.com> wrote in message
news:7c30307f-b03c-4ecc...@p11g2000yqe.googlegroups.com...

Peter Olcott

unread,
Mar 21, 2009, 9:57:35 PM3/21/09
to

"Juha Nieminen" <nos...@thanks.invalid> wrote in message
news:_c7xl.105$Q%4....@read4.inet.fi...

Yes, that is not too bad, but, I want to handle boundary
checks myself. The C++ exception handling infrastructure
most likely has much more overhead than I want to pay for,


blargg

unread,
Mar 21, 2009, 10:51:32 PM3/21/09
to
Peter Olcott wrote:
> Balog Pal wrote:

> > Peter Olcott wrote:
> >> Is there a more concise way of saying this:
> >> Ptr->operator[](0)
> > (*Ptr)[0];
>
> That worked in this simple case. What about this more
> complex case:
>
> Number03 = Array01.Array->operator[](0).
>
> Array->operator[](0).
>
> Array->operator[](0).
>
> Array->operator[](0).
>
> Array->operator[](0).
>
> Array->operator[](0).Number;

Number03 = Array01.Array[0][0].

Array[0][0].

Array[0][0].

Array[0][0].

Array[0][0].

Array[0][0].Number;

I remembered this trick since it was used in the Mac OS Classic era to
get a Pascal-like postfix dereference operator (^ in pascal I believe),
because the OS used "handles" almost everywhere. These were
doubly-indirect pointers, so you'd have for example Foo** h. Instead of
(**h).member or (*h)->member, people sometimes did h[0]->member.

blargg

unread,
Mar 21, 2009, 10:57:18 PM3/21/09
to
Peter Olcott wrote:
> "Juha Nieminen" <nos...@thanks.invalid> wrote in message
> news:_c7xl.105$Q%4....@read4.inet.fi...
> > Balog Pal wrote:
> >> But if you actually want it like that, just use at()
> >> instead of []
> >
> > As a bonus, you'll get boundary checks. (May be just
> > slightly slower, but that's often irrelevant unless
> > you need to index the vector millions of times per
> > second.)
>
> Yes, that is not too bad, but, I want to handle boundary
> checks myself. The C++ exception handling infrastructure
^^^
Your compiler's

> most likely has much more overhead than I want to pay for,

Fixed that for you. The only overhead you'll almost definitely get with
at() is the range checks (so a compare and branch around the code that
throws the exception).

But I still agree; the goal was code that did the same thing, not code
that added in range checks.

Alf P. Steinbach

unread,
Mar 22, 2009, 12:02:31 AM3/22/09
to
* Peter Olcott:

> "Vaclav Haisman" <v.ha...@sh.cvut.cz> wrote in message
> news:49C509E1...@sh.cvut.cz...
>> Peter Olcott wrote, On 21.3.2009 14:03:
>>> "Balog Pal" <pa...@lib.hu> wrote in message
>>> news:gq1nc6$1nhk$1...@news.ett.com.ua...
>>>> "Peter Olcott" <NoS...@SeeScreen.com>
>>>>> Is there a more concise way of saying this:
>>>>> Ptr->operator[](0)
>>>> (*Ptr)[0];
>>>>
>>> That worked in this simple case. What about this more
>>> complex case:
>>>
>>> Number03 = Array01.Array->operator[](0).
>>> Array->operator[](0).
>>> Array->operator[](0).
>>> Array->operator[](0).
>>> Array->operator[](0).
>>> Array->operator[](0).Number;
>> Such deep array structures are highly unlikely. If you do
>> not like
>> (*vecptr)[0] then use reference: std::vector<foo> & v =
>> *vecptr; v[0];.
>
> It is a given (like in geometry, it can't change) design
> requirement that the depth of reference specified above can
> not be changed. I don't want to explain my reasoning because
> that would require disclosing proprietary information.
>
> The above syntax compiles and produce the desired
> functionality. I just want to be able to specify it more
> concisely if possible.

SOLUTION 1.

Define a function 'in' of 7 arguments, then write something like

Number03 = in( Array01, 0, 0, 0, 0, 0, 0 );

Or, if you want a more general solution, under assumption that you cannot change
the type definitions for that structure:


SOLUTION 2.

<code>
#include <iostream>
#include <vector>
#include <stddef.h>

#ifdef _MSC_VER
# pragma warning( disable: 4503 ) // decorated name length exceeded
#endif


//----------------------------------- Silly 6-dimensional vector:

struct NumberHolder
{
double number;
NumberHolder( double x ): number( x ) {}
};

template< typename T >
struct VecPtrHolder
{
T* array;
VecPtrHolder( T& a ): array( &a ) {}
};


typedef std::vector< NumberHolder > Vec1D;
typedef std::vector< VecPtrHolder< Vec1D > > Vec2D;
typedef std::vector< VecPtrHolder< Vec2D > > Vec3D;
typedef std::vector< VecPtrHolder< Vec3D > > Vec4D;
typedef std::vector< VecPtrHolder< Vec4D > > Vec5D;
typedef std::vector< VecPtrHolder< Vec5D > > Vec6D;


//----------------------------------- Machinery to index the beast:

template< typename T > struct ElemTypeOf;
template< typename T, typename U > struct ElemTypeOf< std::vector<T, U> >
{
typedef T Type;
};

template< typename V > struct In;
template< typename V > struct In< VecPtrHolder<V> >
{
V* myArray;

In( VecPtrHolder<V>& holder ): myArray( holder.array ) {}

In< typename ElemTypeOf<V>::Type > operator[]( size_t i )
{
return (*myArray)[i];
}
};

template<>
struct In< VecPtrHolder< std::vector< NumberHolder > > >
{
typedef std::vector<NumberHolder> Vec;
Vec* myVecPtr;

In( VecPtrHolder<Vec>& v ): myVecPtr( v.array ) {}

NumberHolder& operator[]( size_t i )
{
return (*myVecPtr)[i];
}
};

template< typename V >
In< VecPtrHolder< V > > in( VecPtrHolder<V> h ) { return h; }


//----------------------------------- Example usage:

int main()
{
using namespace std;

Vec1D v1( 1, 3.14 );
Vec2D v2( 1, v1 );
Vec3D v3( 1, v2 );
Vec4D v4( 1, v3 );
Vec5D v5( 1, v4 );
Vec6D v6( 1, v5 );
VecPtrHolder< Vec6D > array01( v6 );

cout << in( array01 )[0][0][0][0][0][0].number << endl;
}
</code>

For this latter solution it's probably a good idea to extend it to support
const-ness.

But the best of idea of all is perhaps


SOLUTION 3.

To check whether the program logic is sound. It's a common newbie mistake to end
up with huge and/or multi-dimensional arrays. Generally it reflects some failure
in understanding the problem domain.


Cheers & hth.,

- Alf

--
Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
No ads, and there is some C++ stuff! :-) Just going there is good. Linking
to it is even better! Thanks in advance!

Vaclav Haisman

unread,
Mar 22, 2009, 6:08:21 AM3/22/09
to
If find this hard to believe. I have hard time imagining any situations where
such deeply nested arrays are required. You should not let "them" force such
design decisions on you, IMHO. Customers should not have any say about
internal design decisions, only functionality and interfaces. And you can
always argue with them. The notion that customer is always right is wrong and
stupid.

>
> The above syntax compiles and produce the desired
> functionality. I just want to be able to specify it more
> concisely if possible.
>
>

--
VH

Peter Olcott

unread,
Mar 22, 2009, 8:50:07 AM3/22/09
to

"blargg" <blarg...@gishpuppy.com> wrote in message
news:blargg.ei3-A5A91...@sn-ip.vsrv-sjc.supernews.net...

So it may not be portable?


Peter Olcott

unread,
Mar 22, 2009, 8:55:17 AM3/22/09
to

"Vaclav Haisman" <v.ha...@sh.cvut.cz> wrote in message
news:49C60E15...@sh.cvut.cz...

The architecture that I designed inherently requires this
level of nesting to provide a design that has maximum
robustness, with code that executes as fast as possible.
Changing this requirement reduces either the degree of
robustness or performance.

Peter Olcott

unread,
Mar 22, 2009, 9:02:35 AM3/22/09
to

"Alf P. Steinbach" <al...@start.no> wrote in message
news:gq4d8r$js4$1...@news.motzarella.org...

(1) I do not want to add the cost of function call overhead
or the code bloat of an inline function.

(2) I only really want simpler syntax for exactly and
precisely the original code that I posted.

(3) An addtional requirement is that the simpler syntax must
be standard C++.

Peter Olcott

unread,
Mar 22, 2009, 9:10:46 AM3/22/09
to

"blargg" <blarg...@gishpuppy.com> wrote in message
news:blargg.ei3-49E50...@sn-ip.vsrv-sjc.supernews.net...

> Peter Olcott wrote:
>> "Juha Nieminen" <nos...@thanks.invalid> wrote in message
>> news:_c7xl.105$Q%4....@read4.inet.fi...
>> > Balog Pal wrote:
>> >> But if you actually want it like that, just use at()
>> >> instead of []
>> >
>> > As a bonus, you'll get boundary checks. (May be just
>> > slightly slower, but that's often irrelevant unless
>> > you need to index the vector millions of times per
>> > second.)
>>
>> Yes, that is not too bad, but, I want to handle boundary
>> checks myself. The C++ exception handling infrastructure
> ^^^
> Your compiler's
>> most likely has much more overhead than I want to pay
>> for,

It does not I examined the generated assembly language, and
ran some benchmark testing.

>
> Fixed that for you. The only overhead you'll almost
> definitely get with
> at() is the range checks (so a compare and branch around
> the code that
> throws the exception).

No that is not it. I am always doing the range checks
myself, so if C++ is doing them too, it is wasting time.
Also It is not the overhead of the C++ range checks that is
far too expensive, it is the overhead of the case when an
out-of-bounds exception is thrown that is too expensive.
This is most likely far more expensive than a text output
call.

Balog Pal

unread,
Mar 22, 2009, 9:35:59 AM3/22/09
to

"Peter Olcott" <NoS...@SeeScreen.com>

> No that is not it. I am always doing the range checks myself, so if C++ is
> doing them too, it is wasting time. Also It is not the overhead of the C++
> range checks that is far too expensive, it is the overhead of the case
> when an out-of-bounds exception is thrown that is too expensive. This is
> most likely far more expensive than a text output call.

I don't understand this. You said that range check is already done. Using []
requires the index being correct, if it isn't you have UB. So you can't
have any case where at() would throw.
So how can you have any kind of throw overhead here?

Your comments on inline functions from other message sound fishy too -- if
the function gets inlined you will have the same code as with manual
insertion. without any cost in space or time. If the compiler choses not
to inline it, there's certainly a difference, but it becomes increasingly
rare and with good chances the optimizer got the calculations better.

Source is normally written for readability, most programmers would
definitely prefer


in( Array01, 0, 0, 0, 0, 0, 0 );

to any of the alternatives.
Can you create it as inline func, compile both the original and that version
with assembly listing enabled, then post the result if you see difference in
it?

In case the compiler fails to do a sensible job, I'd probably create a
macro...


Peter Olcott

unread,
Mar 22, 2009, 10:39:16 AM3/22/09
to

"Balog Pal" <pa...@lib.hu> wrote in message
news:gq5ene$k96$1...@news.ett.com.ua...

>
> "Peter Olcott" <NoS...@SeeScreen.com>
>
>> No that is not it. I am always doing the range checks
>> myself, so if C++ is
>> doing them too, it is wasting time. Also It is not the
>> overhead of the C++
>> range checks that is far too expensive, it is the
>> overhead of the case
>> when an out-of-bounds exception is thrown that is too
>> expensive. This is
>> most likely far more expensive than a text output call.
>
> I don't understand this. You said that range check is
> already done. Using []
> requires the index being correct, if it isn't you have UB.
> So you can't
> have any case where at() would throw.

I don't want to spend a lot of time one this, suffice it to
say that the solution does not meet the spec that it be
semantically identical to the original code. ALL that I am
looking for is more concise syntax for the exact code that I
posted. The double indexed solution would exactly meet this
spec as long as it is portable.

Peter Olcott

unread,
Mar 22, 2009, 10:41:17 AM3/22/09
to

"blargg" <blarg...@gishpuppy.com> wrote in message
news:blargg.ei3-A5A91...@sn-ip.vsrv-sjc.supernews.net...

Do you think that it is portable? I tested it and it did
work on MSVC++.


Juha Nieminen

unread,
Mar 22, 2009, 11:00:15 AM3/22/09
to
Peter Olcott wrote:
> I don't want to spend a lot of time one this, suffice it to
> say that the solution does not meet the spec that it be
> semantically identical to the original code.

That means that your original spec requires unchecked vector indexing,
which causes UB when the index is out of boundaries?

Maybe you should rethink your specs.

Juha Nieminen

unread,
Mar 22, 2009, 11:03:00 AM3/22/09
to
Peter Olcott wrote:
>>>>> Number03 = Array01.Array->operator[](0).
>>>>> Array->operator[](0).
>>>>> Array->operator[](0).
>>>>> Array->operator[](0).
>>>>> Array->operator[](0).
>>>>> Array->operator[](0).Number;

>> Define a function 'in' of 7 arguments, then write

>> something like
>>
>> Number03 = in( Array01, 0, 0, 0, 0, 0, 0 );
>
> (1) I do not want to add the cost of function call overhead
> or the code bloat of an inline function.

Could you please explain exactly how does the inline function
introduce code bloat that your original code doesn't already have?

Peter Olcott

unread,
Mar 22, 2009, 12:08:21 PM3/22/09
to

"Juha Nieminen" <nos...@thanks.invalid> wrote in message
news:Eqsxl.95$x74...@read4.inet.fi...

I really don't want to waste a fraction of a second on
anything at all else besides the problem at hand. I already
know that my design is optimal, thus any and all of these
aspects are off-topic.


litb

unread,
Mar 22, 2009, 1:39:54 PM3/22/09
to
On 22 Mrz., 02:54, "Peter Olcott" <NoS...@SeeScreen.com> wrote:
> That looks like it works, could you please explain why it
> works?
>
> "litb" <litb...@googlemail.com> wrote in message

> There is still this way:
>
> =
> Array03.Array[0][0].Array[0][0].Array[0][0].Array[0][0].Array[0]
> [0].Array[0][0].Number;

I'm sorry i didnt follow the thread. I thought it's already clear how
that works. Well, basically *p means the same as p[0], because p[x] is
the same as *(p + x). In your case i believe it means exactly the
same, because the type of *p must be complete anyway because you
access members. But i've found situations in the past where the
equivalence broke:

// --snip--
struct X;
void f(X&);
X *getX();
int main() {
X *x = getX();
f(*x);
}
// --snap--

Note how f(x[0]); would not be valid, because it needs the size of X
(to be able to calc the right "offset") which is not known because X
wasn't defined yet.

blargg

unread,
Mar 22, 2009, 2:23:24 PM3/22/09
to
Peter Olcott wrote:

> blargg wrote:
> > Peter Olcott wrote:
> >> Balog Pal wrote:
> >> > Peter Olcott wrote:
> >> >> Is there a more concise way of saying this:
> >> >> Ptr->operator[](0)
> >> > (*Ptr)[0];
> >>
> >> That worked in this simple case. What about this more
> >> complex case:
> >>
> >> Number03 = Array01.Array->operator[](0).
> >> Array->operator[](0).
> >> Array->operator[](0).
> >> Array->operator[](0).
> >> Array->operator[](0).
> >> Array->operator[](0).Number;
> >
> > Number03 = Array01.Array[0][0].
> > Array[0][0].
> > Array[0][0].
> > Array[0][0].
> > Array[0][0].
> > Array[0][0].Number;
[...]

> Do you think that it is portable? I tested it and it did
> work on MSVC++.

It's portable to any standard C++ (and C, if you're not using operator
overloads) compiler. The expression

E1 [E2]

is defined to be equivalent to

*((E1) + (E2))

as long as there is no operator [] overload. In this case, E1 is of type
std::vector<T>*, and E2 is an int, therefore therefore [] can't be
overloaded. So we can transform the expression in an incremental way:

std::vector<T>* v = ...
v->operator[](0); // what we start with
(*v).operator[](0); // convert -> to equivalent dereference
(*v)[0]; // now we don't need explicit operator call
(*(v+0))[0]; // adding zero before dereferencing doesn't matter
(v[0])[0]; // reverse E1 E2 transformation shown above
v[0][0]; // final expression

blargg

unread,
Mar 22, 2009, 2:31:18 PM3/22/09
to

I think he also meant that it perform identically (perhaps even generate
identical code). The [0] as a postfix dereference operator should achieve
this on almost any compiler, and portably (as I detailed in another post).

Peter Olcott

unread,
Mar 22, 2009, 2:35:02 PM3/22/09
to

"blargg" <blarg...@gishpuppy.com> wrote in message
news:blargg.ei3-22...@192.168.1.4...

That is great, thanks.


Peter Olcott

unread,
Mar 22, 2009, 2:47:03 PM3/22/09
to

"litb" <lit...@googlemail.com> wrote in message
news:04c3f502-1492-4ebd...@j39g2000yqn.googlegroups.com...

That is helpful, thanks. I never bothered to learn all of
the pointer syntax because all of this stuff seemed to make
things much more complicated than necessary, thus a
potential source for error that could best be avoided.

I coded with "C" for fifteen years without ever once
dynamically allocating memory. If there is no memory
allocation then memory leaks are impossible.

Currently all of my C++ code only dynamically allocates
memory through STL container member functions. Almost of
this is though std::vector, thus I can use integer
subscripts instead of pointers.


Vaclav Haisman

unread,
Mar 22, 2009, 2:59:01 PM3/22/09
to
Peter Olcott wrote, On 22.3.2009 13:55:
>>>>> That worked in this simple case. What about this more
>>>>> complex case:
>>>>>
>>>>> Number03 = Array01.Array->operator[](0).
>>>>> Array->operator[](0).
>>>>> Array->operator[](0).
>>>>> Array->operator[](0).
>>>>> Array->operator[](0).
>>>>> Array->operator[](0).Number;
>
> The architecture that I designed inherently requires this
> level of nesting to provide a design that has maximum
> robustness, with code that executes as fast as possible.
> Changing this requirement reduces either the degree of
> robustness or performance.
Six levels of indirection is not robust by any kind of measure I can think
of. And it is unlikely to be very fast, too, because it lacks spatial locality.

--
VH

Peter Olcott

unread,
Mar 22, 2009, 3:40:32 PM3/22/09
to

"Vaclav Haisman" <v.ha...@sh.cvut.cz> wrote in message
news:49C68A75...@sh.cvut.cz...

I could explain how it makes perfect sense, but, then I
would have to disclose proprietary information and lose my
competitive edge. Under almost all circumstances the above
construct does not make much sense. I found one where it
does.

When one is attempting to make an extremely robust system.
and have the resulting performance as fast as possible,
while as much as possible leveraging existing technologies,
(to minimize development costs) sometimes this results in
very weird looking code.


litb

unread,
Mar 22, 2009, 4:53:40 PM3/22/09
to
On 22 Mrz., 20:40, "Peter Olcott" <NoS...@SeeScreen.com> wrote:
> >>>>>> That worked in this simple case. What about this more
> >>>>>> complex case:
>
> >>>>>> Number03 = Array01.Array->operator[](0).
> >>>>>>                    Array->operator[](0).
> >>>>>>                    Array->operator[](0).
> >>>>>>                    Array->operator[](0).
> >>>>>>                    Array->operator[](0).
> >>>>>>                    Array->operator[](0).Number;
>

What about something like

NumberType& get_n(Array* a, size_t n) {
while(n-- > 0)
a = (*a)[0];
return a->Number;
}

If you happen to have problems with the raw number, how about

// analog
struct anal {
size_t n;
anal():n(){}
anal& operator()() { n++; return *this; }
operator size_t() { return n; }
};

get_n(Array, anal()()()()());

You could easily expand it to include array dimensions into the parens
and stuff:

struct anal {
Array *a;
anal(Array *a):a(a) {}
anal& operator()(ptrdiff_t p) { a = (*a)[p]; return *this; }
};

anal(Array)(0)(0)(1)(0).a->Number;

You get the idea. There are many ways. Make it a template and
reusable...

Peter Olcott

unread,
Mar 22, 2009, 5:17:36 PM3/22/09
to
I want the resulting code to be as close to this speed as
possible:

double Number03;
Number03 = 12345678.1234;

"litb" <lit...@googlemail.com> wrote in message

news:c7d0a447-16d5-4eb3...@c11g2000yqj.googlegroups.com...

James Kanze

unread,
Mar 23, 2009, 5:03:35 AM3/23/09
to
On Mar 21, 3:54 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
> Balog Pal wrote:
> > But if you actually want it like that, just use at() instead of []

> As a bonus, you'll get boundary checks. (May be just slightly
> slower, but that's often irrelevant unless you need to index
> the vector millions of times per second.)

In any decent implementation, you'll get the bounds checking in
both cases. The difference is that with at(), it's guaranteed,
but it's also guaranteed that you don't get the usually desired
behavior (an assertion failure).


--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Peter Olcott

unread,
Mar 23, 2009, 7:51:27 AM3/23/09
to
I am certain that you are wrong here, The design of C++ is
that you don't ever pay for anything that you don't want.
Bounds checks double the cost of memory access, so they are
not provided by operator[].

"James Kanze" <james...@gmail.com> wrote in message
news:a9247e2c-a8e8-44c1...@h20g2000yqj.googlegroups.com...

Anand Hariharan

unread,
Mar 23, 2009, 8:39:49 AM3/23/09
to
On Mar 23, 6:51 am, "Peter Olcott" <NoS...@SeeScreen.com> wrote:
> I am certain that you are wrong here, The design of C++ is
> that you don't ever pay for anything that you don't want.
> Bounds checks double the cost of memory access, so they are
> not provided by operator[].
>

Look up 'Checked Iterators'.

James' comment was w.r.t what most ("decent") implementations do. The
standard does not mandate what an implementation should (not) provide
as a QoI feature. E.g., a conforming implementation may provide
Garbage Collection.

- Anand

Yannick Tremblay

unread,
Mar 23, 2009, 12:55:10 PM3/23/09
to
In article <-4CdnUQOEOxFpVvU...@giganews.com>,

Peter Olcott <NoS...@SeeScreen.com> wrote:
>
>"blargg" <blarg...@gishpuppy.com> wrote in message
>news:blargg.ei3-49E50...@sn-ip.vsrv-sjc.supernews.net...
>> Peter Olcott wrote:
>>> "Juha Nieminen" <nos...@thanks.invalid> wrote in message
>>> news:_c7xl.105$Q%4....@read4.inet.fi...
>>> > Balog Pal wrote:
>>> >> But if you actually want it like that, just use at()
>>> >> instead of []
>>> >
>>> > As a bonus, you'll get boundary checks. (May be just
>>> > slightly slower, but that's often irrelevant unless
>>> > you need to index the vector millions of times per
>>> > second.)
>>>
>>> Yes, that is not too bad, but, I want to handle boundary
>>> checks myself. The C++ exception handling infrastructure
>> ^^^
>> Your compiler's
>>> most likely has much more overhead than I want to pay
>>> for,

"most likely" would indicate that you have not checked but you are
guessing on prejudices.

>It does not I examined the generated assembly language, and
>ran some benchmark testing.

Ah, so you did some testing. But did you benchmark your application
or a little irrelevant code sample comparing exclusively one throw to
one if() ? If the later, obviously a try-throw-catch is a lot more
expensive than a if. However, typical exception using code use a lot
lot less try-throw-catch than typical return code based code.

You should not compare:

for(int i = 0; i < 1000000 ; ++i)
{
if(foo())
;
}

to

for(int i = 0; i < 1000000 ; ++i)
{
try
{
foo();
}
catch(...) {};
}


but to:

try
{
for(int i = 0; i < 1000000 ; ++i)
foo();
}
catch(...) {};

>>
>> Fixed that for you. The only overhead you'll almost
>> definitely get with
>> at() is the range checks (so a compare and branch around
>> the code that
>> throws the exception).
>
>No that is not it. I am always doing the range checks
>myself, so if C++ is doing them too, it is wasting time.
>Also It is not the overhead of the C++ range checks that is
>far too expensive, it is the overhead of the case when an
>out-of-bounds exception is thrown that is too expensive.
>This is most likely far more expensive than a text output
>call.

But the exception due to an out-of-bound situation should be
exceptional. Error path cost should not be your main priority since
it should only happen exceptionally rarely when something went
exceptionally wrong. If it is a "normal" situation that an
out-of-bound exception gets thrown, then you have a design issue.

blargg

unread,
Mar 23, 2009, 6:46:05 PM3/23/09
to
Peter Olcott wrote:
> James Kanze wrote:

>> Juha Nieminen wrote:
>>> Balog Pal wrote:
>>>> But if you actually want it like that, just use at()
>>>> instead of []
>>>
>>> As a bonus, you'll get boundary checks. (May be just
>>> slightly slower, but that's often irrelevant unless
>>> you need to index the vector millions of times per
>>> second.)
>>
>> In any decent implementation, you'll get the bounds checking
>> in both cases. The difference is that with at(), it's
>> guaranteed, but it's also guaranteed that you don't get
>> the usually desired behavior (an assertion failure).
>
> I am certain that you are wrong here, The design of C++ is
> that you don't ever pay for anything that you don't want.
> Bounds checks double the cost of memory access, so they are
> not provided by operator[].

A boundary violation of vector::operator [] yields undefined behavior. A
good implementation will at the very least do a bounds check when
debugging is enabled. A good one should have a way to disable the check
in a sufficiently optimized release build. If the absence of a check is
of utmost importance, at the very least you should do something like
(&front()) [n], perhaps caching &front() if using it within a loop.

And please stop top-posting and quoting signatures.

0 new messages