invalid access to non-static data member

D

Denis Remezov

Rob said:
Peter Ammon wrote in
in comp.lang.c++:
Here's some short code that exhibits my problem.

--
#include <cstdlib>
using namespace std;

#define CMAX (sizeof (((trie_node*)NULL)->children) \
/ sizeof *(((trie_node*)NULL)->children))

class trie_node {
trie_node* children[26];


enum { cmax = 26 };
trie_node *children[ cmax ];
public:
unsigned child_count(void) const {
unsigned i, result=0;
for (i=0; i < CMAX; i++) {
if (children) result++;
}
return result;
}
};

[...]
--

gcc 3.3 emits this warning:

test.cpp: In member function `unsigned int trie_node::child_count()
const': test.cpp:11: warning: invalid access to non-static data member
`
trie_node::children' of NULL object

Is gcc right to complain? I thought arguments to sizeof are not
evaluated.

Its neither right or wrong, dereferencing a NULL ponter is Undefined
Behaviour (UB).

gcc has detected the UB and issued a warning, but anything it
chooses to do is Ok (as far as the Standard is concerned).


I don't think that this is the case here.

The compiler warns of the expression
((trie_node*)NULL)->children
(twice)

However, since both this and the expression *<the_above> are operands
of sizeof, they are never evaluated. In particular, there is no
dereferencing or access to data as the compiler thinks. Everything
is well defined here.

I've noticed an interesting detail: if you convert trie_node to a POD
(just make all members public), the warnings will go away. I thought
this might have something to do with the compiler attempting
to control the usage of the offsetof macro, which is only defined
for PODs.

Denis
 
P

Peter Ammon

Here's some short code that exhibits my problem.

--
#include <cstdlib>
using namespace std;

#define CMAX (sizeof (((trie_node*)NULL)->children) \
/ sizeof *(((trie_node*)NULL)->children))

class trie_node {
trie_node* children[26];
public:
unsigned child_count(void) const {
unsigned i, result=0;
for (i=0; i < CMAX; i++) {
if (children) result++;
}
return result;
}
};
--

gcc 3.3 emits this warning:

test.cpp: In member function `unsigned int trie_node::child_count() const':
test.cpp:11: warning: invalid access to non-static data member `
trie_node::children' of NULL object

Is gcc right to complain? I thought arguments to sizeof are not evaluated.

Thanks,
-Peter
 
R

Rob Williscroft

Peter Ammon wrote in
in comp.lang.c++:
Here's some short code that exhibits my problem.

--
#include <cstdlib>
using namespace std;

#define CMAX (sizeof (((trie_node*)NULL)->children) \
/ sizeof *(((trie_node*)NULL)->children))

class trie_node {
trie_node* children[26];


enum { cmax = 26 };
trie_node *children[ cmax ];
public:
unsigned child_count(void) const {
unsigned i, result=0;
for (i=0; i < CMAX; i++) {
if (children) result++;
}
return result;
}
};


if you prefer:

#include <iostream>
#include <ostream>
#include <cstdlib>
using namespace std;


template < typename T, std::size_t Z >
char const (&count_as_char_array( T const (&array)[ Z ] ))[ Z ];

#define COUNTOF( X ) sizeof( count_as_char_array( X ) )



class trie_node {
trie_node* children[26];
public:
unsigned child_count(void) const {
unsigned i, result=0;
for (i=0; i < COUNTOF( children ); i++) {
if (children) result++;
}
return result;
}
};

int main()
{
trie_node tn;
cout << tn.child_count() << endl;
}
--

gcc 3.3 emits this warning:

test.cpp: In member function `unsigned int trie_node::child_count()
const': test.cpp:11: warning: invalid access to non-static data member
`
trie_node::children' of NULL object

Is gcc right to complain? I thought arguments to sizeof are not
evaluated.

Its neither right or wrong, dereferencing a NULL ponter is Undefined
Behaviour (UB).

gcc has detected the UB and issued a warning, but anything it
chooses to do is Ok (as far as the Standard is concerned).

Rob.
 
B

Bob Hairgrove

Here's some short code that exhibits my problem.

--
#include <cstdlib>
using namespace std;

#define CMAX (sizeof (((trie_node*)NULL)->children) \
/ sizeof *(((trie_node*)NULL)->children))

class trie_node {
trie_node* children[26];
public:
unsigned child_count(void) const {
unsigned i, result=0;
for (i=0; i < CMAX; i++) {
if (children) result++;
}
return result;
}
};
--

gcc 3.3 emits this warning:

test.cpp: In member function `unsigned int trie_node::child_count() const':
test.cpp:11: warning: invalid access to non-static data member `
trie_node::children' of NULL object

Is gcc right to complain? I thought arguments to sizeof are not evaluated.

Thanks,
-Peter


Just three little things:

1. I think gcc is correct because operator-> needs an object. You
might try sizeof(trie_node::children) or sizeof(this->children)
instead, but read on as to why this is not desirable...
2. Since the array size must be a constant integral value known at
compile time, CMAX could be replaced by that constant.
3. It would be far better to use std::vector<trie_node*> because it
gives you the size() member function for free, and you can fill it up
dynamically, i.e. don't have to worry about elements being NULL.

HTH
 
B

Bob Hairgrove

Peter Ammon wrote in
in comp.lang.c++:
Here's some short code that exhibits my problem.

--
#include <cstdlib>
using namespace std;

#define CMAX (sizeof (((trie_node*)NULL)->children) \
/ sizeof *(((trie_node*)NULL)->children))

class trie_node {
trie_node* children[26];


enum { cmax = 26 };
trie_node *children[ cmax ];
public:
unsigned child_count(void) const {
unsigned i, result=0;
for (i=0; i < CMAX; i++) {
if (children) result++;
}
return result;
}
};


if you prefer:

#include <iostream>
#include <ostream>
#include <cstdlib>
using namespace std;


template < typename T, std::size_t Z >
char const (&count_as_char_array( T const (&array)[ Z ] ))[ Z ];

#define COUNTOF( X ) sizeof( count_as_char_array( X ) )



class trie_node {
trie_node* children[26];
public:
unsigned child_count(void) const {
unsigned i, result=0;
for (i=0; i < COUNTOF( children ); i++) {
if (children) result++;
}
return result;
}
};

int main()
{
trie_node tn;
cout << tn.child_count() << endl;
}
--

gcc 3.3 emits this warning:

test.cpp: In member function `unsigned int trie_node::child_count()
const': test.cpp:11: warning: invalid access to non-static data member
`
trie_node::children' of NULL object

Is gcc right to complain? I thought arguments to sizeof are not
evaluated.

Its neither right or wrong, dereferencing a NULL ponter is Undefined
Behaviour (UB).

gcc has detected the UB and issued a warning, but anything it
chooses to do is Ok (as far as the Standard is concerned).

Rob.


Hi Rob,

Some questions about how this works (or is supposed to work):

(a) Where is "array" [or (&array)] defined?
(b) The code as given doesn't compile on Borland 5.5.1 free compiler.

Errors are:
Error E2285 test_array_stuff.cpp 19: Could not find a match for
'count_as_char_array<T,Z>(trie_node * const *)' in function
trie_node::child_count() const
Error E2109 test_array_stuff.cpp 19: Not an allowed type in function
trie_node::child_count() const

.... and a warning:

Warning W8008 test_array_stuff.cpp 19: Condition is always false in
function trie_node::child_count() const

TIA
 
R

Rob Williscroft

Bob Hairgrove wrote in in
comp.lang.c++:
Hi Rob,

Some questions about how this works (or is supposed to work):

(a) Where is "array" [or (&array)] defined?

Its a paramiter to the unused (and undefined) function
'count_as_char_array'.

COUNTOF( children ) expands to:

sizeof(
count_as_char_array( children )
)

Template argument deduction deduces the template paramiters T and Z,
trie_node * and 26 in this case.

(b) The code as given doesn't compile on Borland 5.5.1 free compiler.

Yep its a bug in the compiler, I tried to workaround it (with 5.6.4)
but with no luck.

Sometimes a similar things can be worked around (with borland compilers)
by adding a non-const overload:

template < typename T, std::size_t Z >
char const (&count_as_char_array( T (&array)[ Z ] ))[ Z ];

But not in this case.
Errors are:
Error E2285 test_array_stuff.cpp 19: Could not find a match for
'count_as_char_array<T,Z>(trie_node * const *)' in function
trie_node::child_count() const

The compiler has automagicly "decayed" the array to a pointer,
this is one of the few cases when it isn't supposed to do that.

Here's an example that works with Borland:

#include <iostream>
#include <ostream>

template < typename T, std::size_t Z >
void f( T (&array)[ Z ] )
{
using namespace std;
cout << "f< T, " << Z << " >()" << endl;
}

int main()
{
char buf[ 1000 ];
f( buf );
}

The Borland compilers seem to have problems with templates when you
use "to much" indirection, i.e. you rely an the compiler instantiating
some thing while its doing something else.
Error E2109 test_array_stuff.cpp 19: Not an allowed type in function
trie_node::child_count() const

... and a warning:

Warning W8008 test_array_stuff.cpp 19: Condition is always false in
function trie_node::child_count() const

The first error is the only one that counts, the second and the
warning are side effects of the compilers first failure.

Rob.
 
R

Rob Williscroft

Denis Remezov wrote in in
comp.lang.c++:
I don't think that this is the case here.

The compiler warns of the expression
((trie_node*)NULL)->children
(twice)

However, since both this and the expression *<the_above> are operands
of sizeof, they are never evaluated. In particular, there is no
dereferencing or access to data as the compiler thinks. Everything
is well defined here.

Yes, IIUC you are right, derefrencing is a form of evaluation, so
everything sould be fine (i.e. no derefrencing happens).
I've noticed an interesting detail: if you convert trie_node to a POD
(just make all members public), the warnings will go away. I thought
this might have something to do with the compiler attempting
to control the usage of the offsetof macro, which is only defined
for PODs.

Probably, also worth noting it is only a warning.

Rob.
 
P

Peter Ammon

Bob said:
Here's some short code that exhibits my problem.

--
#include <cstdlib>
using namespace std;

#define CMAX (sizeof (((trie_node*)NULL)->children) \
/ sizeof *(((trie_node*)NULL)->children))

class trie_node {
trie_node* children[26];
public:
unsigned child_count(void) const {
unsigned i, result=0;
for (i=0; i < CMAX; i++) {
if (children) result++;
}
return result;
}
};
--

gcc 3.3 emits this warning:

test.cpp: In member function `unsigned int trie_node::child_count() const':
test.cpp:11: warning: invalid access to non-static data member `
trie_node::children' of NULL object

Is gcc right to complain? I thought arguments to sizeof are not evaluated.

Thanks,
-Peter



Just three little things:

1. I think gcc is correct because operator-> needs an object. You
might try sizeof(trie_node::children) or sizeof(this->children)
instead, but read on as to why this is not desirable...


I'd like to be able to evaluate this macro outside of the scope (or do I
mean namespace?) of trie_node, but neither of those suggestions seem to
let me. Is there a workaround?
2. Since the array size must be a constant integral value known at
compile time, CMAX could be replaced by that constant.
3. It would be far better to use std::vector<trie_node*> because it
gives you the size() member function for free,

Ok, but how do I access this size outside of the scope of trie_node?
And is there a way to express that the size of each vector is always fixed?
and you can fill it up
dynamically, i.e. don't have to worry about elements being NULL.

Ok, but is there a way to use std::vector without impacting memory
useage so much? I have to make ~ 1.4 million instances of this class.
I find that with an array of 16 trie_node*s, I use 104 MB of RAM, but
when I try it with a vector, I use...well, it climbs past 250 MB and
then it crashes on function entry for some reason.

Incidentally, a NULL element means that there's no child for that
character index, so it's useful information.

Thanks for your thoughts,
-Peter
 
R

Rob Williscroft

Peter Ammon wrote in
in comp.lang.c++:
Here's some short code that exhibits my problem.

--

Code wrapped for usenet :).

#include <iostream>
#include <ostream>
#include <cstdlib>

template < typename T, typename Class, std::size_t Z >
char const (&count_member_array_helper(
T const (Class::*array)[ Z ] ))[ Z ]
;

/* This overload is needed by gcc (g++) 3.2, CbuilderX (EDG)
and Borland 5.6.4, gcc 3.4 and MSVC 7.1 didn't need it.
*/
template < typename T, typename Class, std::size_t Z >
char const (&count_member_array_helper( T (Class::*array)[ Z ] ))[ Z ];

#define COUNTOF_MEBER_ARRAY( C, X ) \
sizeof( count_member_array_helper( &C::X ) )


class trie_node
{
/* *MUST* be accesable (public) for the macro to work
*/
public:
trie_node* children[26];

public:
/* Just for demonstration purposes!
*/
trie_node()
{
for (
std::size_t i=0;
i < COUNTOF_MEBER_ARRAY( trie_node, children );
i++
)
{
children[ i ] = i & 1 ? this : 0;
}
}

public:
std::size_t child_count(void) const
{
std::size_t result=0;
for (
std::size_t i=0;
i < COUNTOF_MEBER_ARRAY( trie_node, children );
i++
)
{
if (children) result++;
}
return result;
}
};

int main()
{
using namespace std;

size_t sz = COUNTOF_MEBER_ARRAY( trie_node, children );
cout
<< "Size of trie_node::children: " << sz
<< endl
;

cout
<< "trie_node().child_count(): " << trie_node().child_count()
<< endl
;
}


Rob.
 
B

Bob Hairgrove

[snip]
I'd like to be able to evaluate this macro outside of the scope (or do I
mean namespace?) of trie_node, but neither of those suggestions seem to
let me. Is there a workaround?


Ok, but how do I access this size outside of the scope of trie_node?
And is there a way to express that the size of each vector is always fixed?

I don't really understand what you are doing. You want a fixed size
(array or vector), so why jump through hoops when you can merely
declare a constant somewhere and be done with it?

You can reserve memory in the inialitzation list of the constructor of
trie_node by doing this, e.g.:

const int cmax = 26;
trie_node::trie_node() : children(cmax) { /* ... */}

Or you could pass the size as a constructor argument.

If you want to get the vector size, and the size isn't a global
constant, just make a public member function which returns either
Ok, but is there a way to use std::vector without impacting memory
useage so much? I have to make ~ 1.4 million instances of this class.
I find that with an array of 16 trie_node*s, I use 104 MB of RAM, but
when I try it with a vector, I use...well, it climbs past 250 MB and
then it crashes on function entry for some reason.

Sounds like there might be some temporary copies which never get
deleted. I wonder if you really need that many objects? Perhaps most
of them are null pointers. In general, the vector shouldn't add so
much overhead; of course, since each object has its own vector, then
you get 1.4M vectors, and ... well, that's a lot of overhead!
Incidentally, a NULL element means that there's no child for that
character index, so it's useful information.

Without knowing your algorithm, it is hard to say ... but if you could
find another way other than using null pointers, you could probably
save a lot on resources.

One way might be to maintain the pointers in just one huge vector
managed by a separate class. For each new object created, there would
be a unique index assigned to that object which would have exclusive
access to a certain range of elements. That way, you could at least
allocate all the memory for the vector at once.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
KetoBurn
Top