initializing table in class

J

jimmij

Hi,

Please look at the code bellow

/*******************/
class ctab
{
private:
static const unsigned n=48;

public:
int tab[n];
//int tab[n]={0}; //error, but outside class is good

ctab();
};
/*******************/

I would like to initialize each element of tab to zero.

It can be done in constructor (in a loop or by memset), but the perfect
would be if I will be able to declare and initialize table like in
commented line.

So two questions:
1.Why it is imposible to do that in class, what is a reason for that?
2.What is a best way to solve my problem? In real code I have several
arrays, each has several dimensions, so loops will slow down program and
extend code. Is memset the only choice?

Thanks in advance,
 
R

roberts.noah

jimmij said:
Hi,

Please look at the code bellow

/*******************/
class ctab
{
private:
static const unsigned n=48;

public:
int tab[n];
//int tab[n]={0}; //error, but outside class is good

ctab();
};
2.What is a best way to solve my problem? In real code I have several
arrays, each has several dimensions, so loops will slow down program and
extend code. Is memset the only choice?

Implement ctab() as so:

ctab::ctab() : tab(0) { /* code */ }
 
V

Victor Bazarov

jimmij said:
Please look at the code bellow

/*******************/
class ctab
{
private:
static const unsigned n=48;

public:
int tab[n];
//int tab[n]={0}; //error, but outside class is good

ctab();
};
/*******************/

I would like to initialize each element of tab to zero.

It can be done in constructor (in a loop or by memset), but the perfect
would be if I will be able to declare and initialize table like in
commented line.

You cannot. The language does not allow that.
So two questions:
1.Why it is imposible to do that in class, what is a reason for that?

Because initialisation of non-static members is the task for the
constructor. It's done in the initialiser list of the constructor for
all members except arrays. For arrays you need to do it inside the
constructor's body.
2.What is a best way to solve my problem?

Use memset.
> In real code I have several
arrays, each has several dimensions, so loops will slow down program and
extend code. Is memset the only choice?

You could also have a static instance of your file with all those arrays
initialised (to zero), and construct your objects by copying them from the
static instance. Under the covers the compiler will still probably make
a call to memcpy (or memset).

V
 
T

TB

(e-mail address removed) skrev:
jimmij said:
Hi,

Please look at the code bellow

/*******************/
class ctab
{
private:
static const unsigned n=48;

public:
int tab[n];
//int tab[n]={0}; //error, but outside class is good

ctab();
};
2.What is a best way to solve my problem? In real code I have several
arrays, each has several dimensions, so loops will slow down program and
extend code. Is memset the only choice?

Implement ctab() as so:

ctab::ctab() : tab(0) { /* code */ }

class A {
int a[40];
A() : a(0) {}
};

Comeau C/C++ 4.3.3 (Aug 6 2003 15:13:37) for ONLINE_EVALUATION_BETA1
Copyright 1988-2003 Comeau Computing. All rights reserved.
MODE:strict errors C++

"ComeauTest.c", line 3: error: only "()" is allowed as initializer for
array member
"A::a"
A() : a(0) {}
^

1 error detected in the compilation of "ComeauTest.c".
 
J

jimmij

Victor Bazarov said:
Use memset.

I afraid of memset and trying to avoid it because afaik it is not save in
other then int (e.g. float) type. I consider std:vector instead of
array. Can it be a solution?
 
V

Victor Bazarov

jimmij said:
I afraid of memset and trying to avoid it because afaik it is not
save in other then int (e.g. float) type. I consider std:vector
instead of array. Can it be a solution?

Well.. I am not the one to help you overcome your fears. You have to
deal with them on your own. However, 'memset' is safe with 'float'.
It's not necessarily safe with arrays of pointers, you'd need to use
'generate' or 'generate_n' for them. It is definitely not good for
arrays of objects, but those must have their own constructors.

V
 
P

Peter_Julian

| Hi,
|
| Please look at the code bellow
|
| /*******************/
| class ctab
| {
| private:
| static const unsigned n=48;
|
| public:
| int tab[n];
| //int tab[n]={0}; //error, but outside class is good
|
| ctab();
| };
| /*******************/
|
| I would like to initialize each element of tab to zero.

Then you are using the wrong container. Primitive arrays must be valid
at compile time with a known fixed size. All the features you seek and
more have already been invented. Here is a simple class composed of a
templated std:vector.

The container can be initialized with any size with any value using any
type and grows as required dynamically. I could have provided a
operator[], push_back(...) and pop_back() member functions as an
interface to the private std::vector.

#include <iostream>
#include <ostream>
#include <algorithm> // for std::copy
#include <iterator> // for std::eek:stream_iterator
#include <vector>

template< class T >
class Container
{
std::vector< T > v;
public:
Container() : v() { }
Container(unsigned sz, T t) : v(sz, t) { }
~Container() { }

friend std::eek:stream& operator<<(std::eek:stream&, Container< T >&);
};

/* overload operator<< */
template< class T >
std::eek:stream& operator<<(std::eek:stream& os, Container< T >& cont)
{
os << "size = " << cont.v.size();
os << "\n";
std::copy( cont.v.begin(),
cont.v.end(),
std::eek:stream_iterator<T>(os, " ") );
os << std::endl;
return os;
}

int main()
{
// ie: type integer, 10 elements, all initialized to 0
Container<int> container(10, 0);

std::cout << container; // done !

return 0;
}

/*
size = 10
0 0 0 0 0 0 0 0 0 0
*/

And if i need a container of std::string, long, char, or for that matter
*any* user-type i need not modify a single line of class code (except
for perhaps a #include ).

Try doing that with an array. By the way, its entirely pheasable to
complete the project with just a primitive array. Its just that the
amount of extra work and extra code required to duplicate the features
here would be reinventing the wheel.

Additionally, a std::vector is the simplest of the dynamic STL
containers available. Others include std::list, std::queue, std::deque,
etc...

|
| It can be done in constructor (in a loop or by memset), but the
perfect
| would be if I will be able to declare and initialize table like in
| commented line.
|
| So two questions:
| 1.Why it is imposible to do that in class, what is a reason for that?
| 2.What is a best way to solve my problem? In real code I have several
| arrays, each has several dimensions, so loops will slow down program
and
| extend code. Is memset the only choice?
|
| Thanks in advance,
| --
| jimmij
 
B

BobR

jimmij wrote in message ...
I afraid of memset and trying to avoid it because afaik it is not save in
other then int (e.g. float) type. I consider std:vector instead of
array. Can it be a solution?

#include <iostream>
#include <ostream>
#include <vector>

class VecArray{
std::vector<double> vDbl;
public:
VecArray(): vDbl(4, 077.14150){}
double GetNum(size_t indx){
if( indx > vDbl.size()-1){ return 0.0;}
return vDbl.at(indx);
}
size_t GetSize(){ return vDbl.size();}
};

int main(){
VecArray Varr;
size_t vaSize = Varr.GetSize();
for(size_t i(0); i < vaSize; ++i){
std::cout<<" Varr.GetNum( "<<i<<" )="<<Varr.GetNum( i )<<std::endl;
} //for(i)
return 0;
} // main() end
 
D

Dietmar Kuehl

Implement ctab() as so:

ctab::ctab() : tab(0) { /* code */ }

Nope. This is illegal syntax for an array. However, the following
*is* legal and does what the original author intended, i.e. it
default initializes every element which in the case of built-in
types means zero initialization:

ctab::ctab(): tab() { /* other initialization */ }

It is worth noting that all POD struct types can be initialized
this way and go uninitialized if neither default- nor
copy-initialization is used.
 
D

Dietmar Kuehl

jimmij said:
I afraid of memset

This is the wrong attitude towards programming: you need to use
what is in order. If this requires "scary" interfaces, this is
what it requires. Of course, the given situation does not require
'memset()' nor use of a 'std::vector': you can just default-initialize
the array member which will initialize all built-in types with zero:

ctab::ctab(): tab() {}

It is quite interesting that this simple solution does elide some
of the more knowledgable authors in this forum...
and trying to avoid it because afaik it is not save in
other then int (e.g. float) type. I consider std:vector instead of
array. Can it be a solution?

'std::vector' might be a solution but it might as well be overkill.
It is hard to tell whether your class requires flexibility in the
number of elements but if it does, 'std::vector' is probably the
better solution. If it does not, however, a built-in array is likely
to be the most appropriate solution.
 
M

Marcus Kwok

Dietmar Kuehl said:
you can just default-initialize
the array member which will initialize all built-in types with zero:

ctab::ctab(): tab() {}

It is quite interesting that this simple solution does elide some
of the more knowledgable authors in this forum...

So then does this mean that VC++ .NET 2003 (7.1) is not compliant in
this regard, or did I make a stupid mistake in my program?

#include <iostream>
#include <iterator>
#include <cstdlib>

const std::size_t Size = 4;

class UnInit {
int ai[Size];
bool bi[Size];
public:
friend std::eek:stream& operator<<(std::eek:stream& o, const UnInit& u);
};

std::eek:stream&
operator<<(std::eek:stream& o, const UnInit& u)
{
o << "UnInit:\n";
o << "ai = {";
std::copy(u.ai, u.ai + Size, std::eek:stream_iterator<int>(o, ", "));
o << "\b\b}\n";

o << "bi = {";
std::copy(u.bi, u.bi + Size, std::eek:stream_iterator<bool>(o, ", "));
o << "\b\b}";

return o;
}



class Init {
int ai[Size];
bool bi[Size];
public:
Init() : ai(), bi() { }
friend std::eek:stream& operator<<(std::eek:stream& o, const Init& i);
};

std::eek:stream&
operator<<(std::eek:stream& o, const Init& in)
{
o << "Init:\n";
o << "ai = {";
std::copy(in.ai, in.ai + Size, std::eek:stream_iterator<int>(o, ", "));
o << "\b\b}\n";

o << "bi = {";
std::copy(in.bi, in.bi + Size, std::eek:stream_iterator<bool>(o, ", "));
o << "\b\b}";

return o;
}



int main()
{
UnInit u;
Init i;

std::cout << u << "\n\n";
std::cout << i << '\n';

return 0;
}


Output:

UnInit:
ai = {4225084, 4260716, 4260606, 4260716}
bi = {160, 103, 64, 0}

Init:
ai = {4225084, 4260716, 4260606, 4260716}
bi = {160, 103, 64, 0}
 
T

TB

Marcus Kwok skrev:
So then does this mean that VC++ .NET 2003 (7.1) is not compliant in
this regard, or did I make a stupid mistake in my program?

Output:

UnInit:
ai = {4225084, 4260716, 4260606, 4260716}
bi = {160, 103, 64, 0}

Init:
ai = {4225084, 4260716, 4260606, 4260716}
bi = {160, 103, 64, 0}

Borland doesn't default-initialize either.
 
D

Dietmar Kuehl

Marcus said:
So then does this mean that VC++ .NET 2003 (7.1) is not compliant in
this regard, or did I make a stupid mistake in my program?

Yes, I think this an appropriate conclusion! Actually, there is
another thing in which it is non-conforming: Boolean values shall
be output as either '0' for 'false' or '1' for 'true'. Arriving
at values different than these is also not permitted. Of course,
it could be argued that the program has undefined behavior beginning
at the point where uninitialized memory is first accessed: maybe it
would be worth swapping the two output statements to avoid this
situation, too.

To back-up my claim that the above constructor should indeed result
in proper initialization, here are the relevant quotes from the
standard:

8.5 (dcl.init) paragraph 5:

To zero-initialize storage for an object of type T means:
- if T is a scalar type (3.9), the storage is set to the value of 0
(zero) converted to T
[...]
To default-initialize an object of type T means:
- if T is a non-POD class type (clause 9), the default constructor
for T is called (and the initialization is ill-formed if T has no
accessible default constructor);
- if T is an array type, each element is default-initialized;
- otherwise, the storage for the object is zero-initialized


12.6.2 (class.base.init) paragraph 3:

[...] The semantics of a mem-initializer are as follows:
- if the expression-list of the mem-initializer is omitted, the base
class or member subobject is default-initialized (see 8.5).
[...]

I think there was some clean-up in the TC for section 8.5 which
explicitly introduced value-initialization but I don't think that
the overall effect of requiring zero initialization of members is
affected by this change.

BTW, the output resulting from using g++ on a Linux platform is

UnInit:
ai = {1076252660, 134515504, 0, 1076252660}
bi = {0, 0, 0, 0}

Init:
ai = {0, 0, 0, 0}
bi = {0, 0, 0, 0}

which is roughly the same as for icc (Intel's C++ compiler based
on the EDG front-end), except that the values in the uninitialized
values of 'ai' are different.
 

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
474,197
Messages
2,571,040
Members
47,634
Latest member
RonnyBoelk

Latest Threads

Top