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

Are static array pointers thread safe?

27 views
Skip to first unread message

flowst...@gmail.com

unread,
Nov 29, 2007, 8:50:49 PM11/29/07
to
Can multiple threads safely use static array pointers as in the class
below? What are the dangers if not?

class foo{
static int (*a)[26][26];
void createArray();
void writeToArray(int a, int b, int c, int d);
int readFromArray(int a, int b, int c);
}

int (*foo::a)[26][26];

void foo:createArray(){
a = new int[26][26][26];
}

void foo:writeToArray(int a, int b, int c){
a[a][b][c] = d;
}

void foo::readFromArrat(int a, int b, int c){
return a[a][b][c];
}

Doug Harrison [MVP]

unread,
Nov 29, 2007, 9:44:45 PM11/29/07
to
On Thu, 29 Nov 2007 17:50:49 -0800 (PST), flowst...@gmail.com wrote:

>Can multiple threads safely use static array pointers as in the class
>below? What are the dangers if not?
>
>class foo{
> static int (*a)[26][26];
> void createArray();
> void writeToArray(int a, int b, int c, int d);
> int readFromArray(int a, int b, int c);
>}
>
>int (*foo::a)[26][26];
>
>void foo:createArray(){
> a = new int[26][26][26];
>}

I take it your real code creates a dynamically-sized array? If not, and you
always call createArray, and you never assign another value to the pointer
"a", you should just use an actual array variable. Since you aren't
initializing the array contents, it won't even grow your executable, and
since it has static storage duration, there are no stack overflow issues to
worry about.

>void foo:writeToArray(int a, int b, int c){
> a[a][b][c] = d;
>}
>
>void foo::readFromArrat(int a, int b, int c){
> return a[a][b][c];
>}

You need to understand memory visibility rules to answer this question.
Threads created after you call createArray will observe the value
createArray wrote to "a". Threads created before createArray has been
called must use a mutex to reliably observe the value, and of course,
createArray must in that case synchronize on the same mutex as the threads.
That takes care of "a". What about *a? Your writeToArray and readFromArray
functions must use synchronization if multiple threads are to use them
concurrently; the issues are really no different than they were for "a".

--
Doug Harrison
Visual C++ MVP

Joseph M. Newcomer

unread,
Nov 29, 2007, 10:10:12 PM11/29/07
to
The code below is full of bugs and will not compile, but if corrected, it would work. (For
example, WriteToArray takes 4 parameters in the declaration, and 3 parameters in the
implementation, using the value a twice, once as the array name, once as a parameter)

Depends on what you mean by "thread safe". Assuming the values are integers, and DWORD
aligned, it is certainly true that you will not have errors if you just have threads write
fooInstance->writeToArray(1, 2, 3, 5);
while another thread does
fooInstance->writeToArray(1, 2, 3, 7);
the value in a[1][2][3] will be either 5 or 7, and you won't know which. But you cannot
read-and-modify any element of the array, e.g., you cannot do
fooInstance->writeToArray(1, 2, 3, fooInstance->readFromArray(1, 2, 3) + 1);
and expect it will work correctly. It won't. That *does* require explicit
synchronization.

Multiple creates could cause immense problems, but like most examples we see here, all the
really critical and important information is omitted, such as how createArray works.

joe

On Thu, 29 Nov 2007 17:50:49 -0800 (PST), flowst...@gmail.com wrote:

>Can multiple threads safely use static array pointers as in the class
>below? What are the dangers if not?
>
>class foo{
> static int (*a)[26][26];
> void createArray();
> void writeToArray(int a, int b, int c, int d);
> int readFromArray(int a, int b, int c);
>}
>
>int (*foo::a)[26][26];

****
Using a single static like this is a bit strange; it means you can never have more than
one instance of this object anywhere. I presume the goal is a singleton class.

The use of old-fashioned C in a modern environment is more than a little strange also; why
are you not using bounds-checked classes like std::vector? None of this is bounds-safe.
****


>
>void foo:createArray(){
> a = new int[26][26][26];
>}
>
>void foo:writeToArray(int a, int b, int c){
> a[a][b][c] = d;
>}

****
I'm assuming you meant
void foo:writeToArray(int b, int c, int d, int e) {
a[b][c][d] = e;
****


>
>void foo::readFromArrat(int a, int b, int c){
> return a[a][b][c];
>}

****
I'm assuming you meant
int foo::readFromArray(int b, int c, int d) {
return a[b][c][d];
}
****
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

flowst...@gmail.com

unread,
Nov 29, 2007, 10:51:14 PM11/29/07
to
Thanks for the reply.

> I take it your real code creates a dynamically-sized array? If not, and you
> always call createArray, and you never assign another value to the pointer
> "a", you should just use an actual array variable. Since you aren't
> initializing the array contents, it won't even grow your executable, and
> since it has static storage duration, there are no stack overflow issues to
> worry about.

No, it's not dynamically resized. I was under the impression that you
are in fact initializing it when using an actual array variable (int
foo::a[26][26][26];) and all values are defaulting to zero. Also, I
was under the impression that static arrays are put on the stack, so
that's exactly what I was worried about (stack overflow). The array is
actually a bit larger, out to 5 dimensions, and so was a bit
concerned, which is why I thought it might be best to create it
dynamically where it would be put on the heap. I've probably confused
a few things though, this is my first forray in thinking about memory
allocation. If my worries however were unfounded, you're right, I
would probably just do it that way.

> You need to understand memory visibility rules to answer this question.
> Threads created after you call createArray will observe the value
> createArray wrote to "a". Threads created before createArray has been
> called must use a mutex to reliably observe the value, and of course,
> createArray must in that case synchronize on the same mutex as the threads.
> That takes care of "a". What about *a? Your writeToArray and readFromArray
> functions must use synchronization if multiple threads are to use them
> concurrently; the issues are really no different than they were for "a".

Ok, thank you. Does it make a difference if I just use a static array
variable (int foo::a[26][26][26];) as you suggested above? Also,
could you please expound on what you mean by reliably observe, like
what the results of an unreliabe observation would be? I should
explain with that last question... I'm not so interested that the
value be absolutely correct, the values are continuously being updated
and read. So if reader thread is reading while writer thread is
updating the value, and reader thread reads the old value instead of
the new one, then that's ok if that is the result of an unreliable
observation. My concern is more with that same situation causing an
application failure. I suppose my real question would be, what happens
in between the time an array value is updated with another value (a[0]
= 1;a[0] = 2;), is that memory space emptied and then filled, leaving
junk in the interim, is it seamless, or...?

> Doug Harrison
> Visual C++ MVP

Thanks for your help Doug,
John

flowst...@gmail.com

unread,
Nov 29, 2007, 11:10:39 PM11/29/07
to
On Nov 29, 7:10 pm, Joseph M. Newcomer <newco...@flounder.com> wrote:
> The code below is full of bugs and will not compile, but if corrected, it would work. (For
> example, WriteToArray takes 4 parameters in the declaration, and 3 parameters in the
> implementation, using the value a twice, once as the array name, once as a parameter)

Yes, it wasn't meant to be useable code, but I thought it would help
explain a bit more what I was thinking vs just "Are static array
pointers thread safe /NT".

>
> Depends on what you mean by "thread safe". Assuming the values are integers, and DWORD
> aligned, it is certainly true that you will not have errors if you just have threads write
> fooInstance->writeToArray(1, 2, 3, 5);
> while another thread does
> fooInstance->writeToArray(1, 2, 3, 7);
> the value in a[1][2][3] will be either 5 or 7, and you won't know which. But you cannot
> read-and-modify any element of the array, e.g., you cannot do
> fooInstance->writeToArray(1, 2, 3, fooInstance->readFromArray(1, 2, 3) + 1);
> and expect it will work correctly. It won't. That *does* require explicit
> synchronization.

I asked Doug this same question, but could you define what you mean by
it not working correctly (app crash, old value, reading junk, etc)?
What I mean by thread safe for this application is it not causing any
memory errors that would result in application failures. Your second
example was what I was wanting to do, if it returned an old value,
that would be ok.

>
> Multiple creates could cause immense problems, but like most examples we see here, all the
> really critical and important information is omitted, such as how createArray works.

The idea is it would be initialized once at application startup.
Multiple creates would not be used. I went into more detail the
direction I was going and why in my previous reply to Doug.


> >int (*foo::a)[26][26];
>
> ****
> Using a single static like this is a bit strange; it means you can never have more than
> one instance of this object anywhere. I presume the goal is a singleton class.

Yes, the goal is to have this be singular. I'm not an expert on the
singleton pattern, but I believe it could be looked at like that yes.

>
> The use of old-fashioned C in a modern environment is more than a little strange also; why
> are you not using bounds-checked classes like std::vector? None of this is bounds-safe.
> ****

The application requires speed to be a priority for reading and
writing to the array. Profiling std::vector vs the above showed vector
to be 3x slower for writes and 2.5x for reads. Bounds-safety can be
checked by the read-write functions using an enum or static const int
defining MAX_SIZE.

As for the rest of the corrections below, yes, you got me. I wasn't be
careful and was more trying to convey a general idea rather than
presenting flawless code. My bad, I should have communicated this more
clearly. Thanks for your comments Joe.

John

>
> >void foo:createArray(){
> > a = new int[26][26][26];
> >}
>
> >void foo:writeToArray(int a, int b, int c){
> > a[a][b][c] = d;
> >}
>
> ****
> I'm assuming you meant
> void foo:writeToArray(int b, int c, int d, int e) {
> a[b][c][d] = e;
> ****
>
> >void foo::readFromArrat(int a, int b, int c){
> > return a[a][b][c];
> >}
>
> ****
> I'm assuming you meant
> int foo::readFromArray(int b, int c, int d) {
> return a[b][c][d];}
>
> ****
> Joseph M. Newcomer [MVP]

> email: newco...@flounder.com

Doug Harrison [MVP]

unread,
Nov 29, 2007, 11:49:15 PM11/29/07
to
On Thu, 29 Nov 2007 19:51:14 -0800 (PST), flowst...@gmail.com wrote:

>No, it's not dynamically resized. I was under the impression that you
>are in fact initializing it when using an actual array variable (int
>foo::a[26][26][26];) and all values are defaulting to zero.

Yes, objects with static storage duration are zero-initialized during
program startup. I was talking about non-default initialization. In
old-timey terms, your (uninitialized) array's storage would be reserved in
the BSS section of the executable, where it takes up no space, as opposed
to the DATA section, where it would tend to be a full-sized image of the
array (at least in older linkers).

>Also, I
>was under the impression that static arrays are put on the stack, so
>that's exactly what I was worried about (stack overflow).

Objects with static storage duration do not live on the stack. They live in
a separate area of memory dedicated to them. These objects include all
globals, static data members of classes, and local statics.

>The array is
>actually a bit larger, out to 5 dimensions, and so was a bit
>concerned, which is why I thought it might be best to create it
>dynamically where it would be put on the heap. I've probably confused
>a few things though, this is my first forray in thinking about memory
>allocation. If my worries however were unfounded, you're right, I
>would probably just do it that way.

As long as you don't explicitly initialize it, and all the array bounds are
constants, I think you'd be fine using a static array. I suppose there
might be a small delay zero-initializing a huge array at program startup,
but I find it hard to imagine it would be noticeable. For security reasons,
NT-based Windows only provides zero-initialized pages of memory to
processes, so I wonder, does the NT loader even have to zero out the BSS?
It would seem to be redundant.

>Ok, thank you. Does it make a difference if I just use a static array
>variable (int foo::a[26][26][26];) as you suggested above?

Nope. (Of course, all the createArray concerns become moot.)

>Also,
>could you please expound on what you mean by reliably observe, like
>what the results of an unreliabe observation would be?

Multiple CPUs in a weakly-ordered memory system (e.g. SMP Itanium) can
observe all sorts of strange things in the absence of synchronization, such
as reads/writes appearing out of order, writes being indefinitely delayed,
etc. So by "reliable", I mean the participating threads should observe
memory consistently. Google for "memory visibility", "mutex", and "memory
barrier", and you will turn up a lot of hits on this topic.

>I should
>explain with that last question... I'm not so interested that the
>value be absolutely correct, the values are continuously being updated
>and read. So if reader thread is reading while writer thread is
>updating the value, and reader thread reads the old value instead of
>the new one, then that's ok if that is the result of an unreliable
>observation. My concern is more with that same situation causing an
>application failure.

In and of itself, it won't cause a crash, and since ints are read/written
atomically, you won't get any word-tearing. You would have problems,
though, if you are doing read-modify-write cycles, such as ++x. When two
unsynchronized threads do that at the same time, a typical failure mode is
for x to appear to have been incremented only once.

>I suppose my real question would be, what happens
>in between the time an array value is updated with another value (a[0]
>= 1;a[0] = 2;), is that memory space emptied and then filled, leaving
>junk in the interim, is it seamless, or...?

Given that we're talking about ints, because int writes are atomic, another
thread reading a[0] after one or the other of those writes will observe it
to have either the value 1 or 2, or possibly some previous value if the
memory system is weakly ordered. That's assuming the writes actually happen
as you wrote them, but they may not:

1. Because "a" isn't volatile, writing to it doesn't constitute "observable
behavior". This means the compiler could omit writing 1 and postpone
writing 2 until you do something that causes observable behavior, such as
calling an opaque library function that could conceivably have access to
a[0]. Similar concerns apply to writing to different elements of the array;
the compiler can reorder these writes as it sees fit, as long as it doesn't
change the observable behavior of the abstract machine upon which the
language is based. (Significantly, that abstract machine is
single-threaded.)

2. Even if you make "a" volatile, unless "volatile" has memory barrier
semantics, it won't help much in a weakly-ordered memory system. So if the
compiler doesn't get you with its reordering, the hardware will.

To sum up, if you're not using synchronization, you need to use volatile,
and you should be well aware of the pitfalls inherent to not using
synchronization. However, if you're using synchronization, you don't need
volatile, because synchronization provides the desired memory consistency
between the threads; indeed, the only thing using volatile on top of
synchronization does is kill performance.

--

Joseph M. Newcomer

unread,
Nov 30, 2007, 2:12:27 AM11/30/07
to
See below

On Thu, 29 Nov 2007 20:10:39 -0800 (PST), flowst...@gmail.com wrote:

>On Nov 29, 7:10 pm, Joseph M. Newcomer <newco...@flounder.com> wrote:
>> The code below is full of bugs and will not compile, but if corrected, it would work. (For
>> example, WriteToArray takes 4 parameters in the declaration, and 3 parameters in the
>> implementation, using the value a twice, once as the array name, once as a parameter)
>
>Yes, it wasn't meant to be useable code, but I thought it would help
>explain a bit more what I was thinking vs just "Are static array
>pointers thread safe /NT".

*****
The concept that static array pointers may or may not be safe is an irrelevant discussion.
All you care about is the information referenced during an operation, and whether or not
it is thread safe. Whether it is referenced by a pointer, or directly, or through
nineteen levels of indirection is irrelevant. What matters is whether or not the access
path and the value are thread-safe, and the answer is, generally, "never". There are
limited situations in which you might get away with this, such as "write once constants",
where you set values and never modify them, or simple read/write of aligned data where the
order of modification is irrelevant and the nondeterministic effects do not impact the
algorithm, but generally, data access is not thread safe unless you provide the safety
yourself.
****


>
>>
>> Depends on what you mean by "thread safe". Assuming the values are integers, and DWORD
>> aligned, it is certainly true that you will not have errors if you just have threads write
>> fooInstance->writeToArray(1, 2, 3, 5);
>> while another thread does
>> fooInstance->writeToArray(1, 2, 3, 7);
>> the value in a[1][2][3] will be either 5 or 7, and you won't know which. But you cannot
>> read-and-modify any element of the array, e.g., you cannot do
>> fooInstance->writeToArray(1, 2, 3, fooInstance->readFromArray(1, 2, 3) + 1);
>> and expect it will work correctly. It won't. That *does* require explicit
>> synchronization.
>
>I asked Doug this same question, but could you define what you mean by
>it not working correctly (app crash, old value, reading junk, etc)?
>What I mean by thread safe for this application is it not causing any
>memory errors that would result in application failures. Your second
>example was what I was wanting to do, if it returned an old value,
>that would be ok.

****
You might get obsolete values, you might produce erroneous values, updated values will be
overwritten by obsolete values, and so on. If the obsolete values or erroneous values
would affect the correctness of the access to the data (not the data itself), then
definitely you will get an app crash. So it depends on how the pointer value is set and
manipulated.
****


>
>>
>> Multiple creates could cause immense problems, but like most examples we see here, all the
>> really critical and important information is omitted, such as how createArray works.
>
>The idea is it would be initialized once at application startup.
>Multiple creates would not be used. I went into more detail the
>direction I was going and why in my previous reply to Doug.

****
That's a "write once constant", and therefore becomes irrelevant to the discussion of
thread safety because there is no concurrent modification. Thread safety is only an issue
when threads can modify values concurrent with other threads reading them. If the use of
stale data and the resetting of new values to use stale data don't affect your algorithm,
you don't need to lock. We discovered interesting algorithms in our big 16-way
multiprocessor back in 1976 or so, such as no need to lock values at boundaries of certain
kinds of convolution algorithms (where, for partition A to compute the value at the border
of A|B, some values from the B partition must be read and modified. The effect is a
slight anomaly in early iterations which quickly converges to enough accuracy after a few
hundred iterations that the errors are below the significance threshold required for the
real-world result)
****


>
>
>> >int (*foo::a)[26][26];
>>
>> ****
>> Using a single static like this is a bit strange; it means you can never have more than
>> one instance of this object anywhere. I presume the goal is a singleton class.
>
>Yes, the goal is to have this be singular. I'm not an expert on the
>singleton pattern, but I believe it could be looked at like that yes.
>
>>
>> The use of old-fashioned C in a modern environment is more than a little strange also; why
>> are you not using bounds-checked classes like std::vector? None of this is bounds-safe.
>> ****
>
>The application requires speed to be a priority for reading and
>writing to the array. Profiling std::vector vs the above showed vector
>to be 3x slower for writes and 2.5x for reads. Bounds-safety can be
>checked by the read-write functions using an enum or static const int
>defining MAX_SIZE.

****
When you measure performance, it is only valid to measure it in the release version. It
is never valid to measure performance in the debug version, and it is problematic if
measuring performance of unoptimized code is indicative of anything other than the need to
turn on compiler optimizations. Often, bounds checks are optimized away by value
propagation and assertion propagation (which has nothing to do with the ASSERT statement).
****

email: newc...@flounder.com

Joseph M. Newcomer

unread,
Nov 30, 2007, 2:21:07 AM11/30/07
to
What amazed me recently was that a student in my course explained to me how static data
was always allocated on the stack, because he'd been assured by "my professor" that this
was so. I suggested that he might have misunderstood the explanation, but he insisted
that this is what he'd been taught. Kind of scary if true.

flowst...@gmail.com

unread,
Nov 30, 2007, 11:30:17 AM11/30/07
to
Excellent reply Doug. You answered all my questions. Will definitely
be doing some research on memory barriers. It's interesting to note
that on just a cursory search on volatile memory barrier semantics,
there seems to be some debate as to its usefulness in regards to
memory barriers. Also, from reading it seems to be hardware dependent,
but looks like my x86 processors fare better. There's much research I
need to do here.

Thanks again!
John

On Nov 29, 8:49 pm, "Doug Harrison [MVP]" <d...@mvps.org> wrote:

flowst...@gmail.com

unread,
Nov 30, 2007, 11:34:07 AM11/30/07
to
Yes, I think I would be a good example of someone who picked up this
information incorrectly as common knowledge. There are quite a few
sites a discussion boards that reference static data as always being
allocated on the stack. I do, however, remember a few stating what
Doug mentioned about it being stored in the BSS section of the exe,
but seeing as how the overwhelming majority thought otherwise I
assumed the same: dangerous behavior!

John

> email: newco...@flounder.com

Joseph M. Newcomer

unread,
Nov 30, 2007, 11:36:39 AM11/30/07
to
Actually, x86 processors have to deal with the hardware level; operations like
InterlockedIncrement, InterlockedDecrement, and so on force, in assembly code, a "memory
barrier" by using the LOCK prefix to an instruction, which forces the pending writes in
the x86 write pipe to be flushed to memory. Unlike some architectures, the x86 does
guarantee that pending writes are always written in FIFO order. The x64 (AMD x86 64-bit)
architecture has operations such as SFENCE, LFENCE, and MFENCE that synchronize loads,
stores, or both. "volatile" seems to be largely a compiler directive dealing with the
suppression of certain optimizations, but its interaction with hardware is essentially
unspecified.
joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com

flowst...@gmail.com

unread,
Nov 30, 2007, 11:42:28 AM11/30/07
to
Thanks for your replies Joe, they were very helpful.

I thought I should mention, the profiling I did was on the release
build, but I didn't have any compiler optimizations turned on. Will
definitely retry it with them turned on. However, one other reason I
opted against std::vector, was the semantics. A multi-dimensional
array can easily be declared int a[1][1][1][1][1], while the vector is
vector<vector<vector<vector<int> > > > > vec_a(5,..... ad inifintum.
Without using multiple defined vectors with typedefs, the vector
notation for larger multi-dimenionsal containers is a bit of a pain.

Thanks again Joe,
John

On Nov 29, 11:12 pm, Joseph M. Newcomer <newco...@flounder.com> wrote:
> See below
>

Giovanni Dicanio

unread,
Nov 30, 2007, 12:06:49 PM11/30/07
to

<flowst...@gmail.com> ha scritto nel messaggio
news:a1319c40-7a92-4d43...@b40g2000prf.googlegroups.com...

> However, one other reason I
> opted against std::vector, was the semantics. A multi-dimensional
> array can easily be declared int a[1][1][1][1][1], while the vector is
> vector<vector<vector<vector<int> > > > > vec_a(5,..... ad inifintum.

If you want high-performance arrays, I think you may try Blitz++.

It's a C++ open source library, developed with high-performance in mind
(they write they have Fortran 77/90 high-level performance):

http://www.oonumerics.org/blitz/

I think that also Boost may offer something for your "multi-index"
requirements, but I don't know if Boost performance is similar to Blitz++...

You may make some tests.

HTH,
Giovanni

flowst...@gmail.com

unread,
Nov 30, 2007, 12:14:17 PM11/30/07
to
Thanks Giovanni, I appreciate the suggestion. I've heard of it before,
but never thought I might need it and had forgotten about it. I'll
definitely run some tests with it. Looks pretty neat from first
glance.

John

On Nov 30, 9:06 am, "Giovanni Dicanio" <giovanni.dica...@invalid.it>
wrote:
> <flowstudi...@gmail.com> ha scritto nel messaggionews:a1319c40-7a92-4d43...@b40g2000prf.googlegroups.com...

Joseph M. Newcomer

unread,
Nov 30, 2007, 12:30:39 PM11/30/07
to
I'm not sure how this "common knowledge" came about, since it is obvious from the name
'static' that it is NOT allocated on the stack! That is 'auto'. On the other hand, there
are another set of myths, that data types like CString, CArray, std::string, std::vector,
etc. are allocated on the stack, and those are equally untrue; what is allocated on the
stack is a reference to heap-allocated storage. There seems to be endless confusion about
how allocation works; I've even had one correspondent assure me that he would not use
malloc because that caused the space to be allocated on the disk, which would really slow
things down!
joe

email: newc...@flounder.com

Doug Harrison [MVP]

unread,
Nov 30, 2007, 1:02:21 PM11/30/07
to
On Fri, 30 Nov 2007 08:30:17 -0800 (PST), flowst...@gmail.com wrote:

>Excellent reply Doug. You answered all my questions. Will definitely
>be doing some research on memory barriers. It's interesting to note
>that on just a cursory search on volatile memory barrier semantics,
>there seems to be some debate as to its usefulness in regards to
>memory barriers.

VC2005 does add memory barrier semantics to volatile, for those
architectures for which it matters, which makes the performance of volatile
even worse (far worse). Rather than sanctifying volatile for
multithreading, this is another reason to avoid it when you can, which is
*all of the time* if you use synchronization.

>Also, from reading it seems to be hardware dependent,
>but looks like my x86 processors fare better. There's much research I
>need to do here.

Don't get too hung up on memory barriers. If you always use synchronization
such as mutexes (the Windows CRITICAL_SECTION is a type of mutex), you can
remain blissfully ignorant of memory barriers. Don't get too hung up on
volatile. If you always use synchronization, you can remain blissfully
ignorant of volatile. It's only when you don't use synchronization and thus
don't benefit from the memory visibility properties implied by it that you
need to get into this lower level stuff.

Giovanni Dicanio

unread,
Nov 30, 2007, 1:53:29 PM11/30/07
to

"Joseph M. Newcomer" <newc...@flounder.com> ha scritto nel messaggio
news:m0i0l3tg8k4dqti3g...@4ax.com...

> data types like CString, CArray, std::string, std::vector,
> etc. are allocated on the stack, and those are equally untrue; what is
> allocated on the
> stack is a reference to heap-allocated storage.

CString, std::string, std::vector, etc. class *instances* are allocated on
the stack, sure, if we do:

CString name;
std::vector< int > v(10);
...

But, the class *implementation* can do whatever it wants: for example, they
could apply an optimization that, for small strings (e.g. 30 characters),
the char/TCHAR array is allocated on the stack, and for bigger strings the
array is allocated on the heap (e.g. using new). Allocating small strings on
the stack may help avoid heap fragmentation.

IIRC, ATL string helper conversions like C<X>2<Y> (e.g. CA2W, etc.), use
this kind of optimization (stack allocation for small strings, heap
allocation for bigger ones).

Of course, I do think that a 10,000 items vector is allocated on the heap :)
by a well-written std::vector implementation.

Giovanni


Doug Harrison [MVP]

unread,
Nov 30, 2007, 2:18:52 PM11/30/07
to
On Fri, 30 Nov 2007 18:06:49 +0100, "Giovanni Dicanio"
<giovanni...@invalid.it> wrote:

>
><flowst...@gmail.com> ha scritto nel messaggio
>news:a1319c40-7a92-4d43...@b40g2000prf.googlegroups.com...
>
>> However, one other reason I
>> opted against std::vector, was the semantics. A multi-dimensional
>> array can easily be declared int a[1][1][1][1][1], while the vector is
>> vector<vector<vector<vector<int> > > > > vec_a(5,..... ad inifintum.

It's not just the clumsier syntax; vectors of vectors use non-contiguous
memory, while arrays are always contiguous.

>If you want high-performance arrays, I think you may try Blitz++.
>
>It's a C++ open source library, developed with high-performance in mind
>(they write they have Fortran 77/90 high-level performance):
>
>http://www.oonumerics.org/blitz/
>
>I think that also Boost may offer something for your "multi-index"
>requirements, but I don't know if Boost performance is similar to Blitz++...
>
>You may make some tests.

Yes, vector usage is best confined to 1D arrays. If you aren't bound to the
[][][] syntax, you can simulate a multidimensional array with a 1D array.
You could write a class that overloads operator() for element access and
performs the necessary arithmetic to index the array. I'd be surprised if
Boost doesn't provide a dynamic multidimensional array class.

0 new messages