what is happening to elements in vector ?

I

imutate

I have a std::vector with each element being a class, I push_back
elements and then store values in the class object, later I look at
these objects and the values are null. In essence:

class celement
{
public:
int x[3];
...

class vec
{
public:
std::vector<celement> v;
...

void vec::addelement()
{
celement t;
v.push_back(t);
}

void vec::buildmono()
{
addelement();
v.end() -> x[0] = -1;
...

void vec::buildmono()
{
for (i = 0; i < 10; i++)
buildmono();

Later I look through v and none of x[0]s are -1 they are all 0.
for (i = 0; i < 10; i++)
cout << v.x[0] ..


If there is no obvious explanation then I can post more code.
 
M

Moonlit

Hi,

I didn't look at your code carefully (it's quite late here) but I saw

v.end()->

v.end() is pointing one past the last element, i.e.illegal

make that

v.rbegin()->




Regards, Ron AF Greve

http://moonlit.xs4all.nl
 
S

Salt_Peter

I have a std::vector with each element being a class, I push_back
elements and then store values in the class object, later I look at
these objects and the values are null. In essence:

std::vectors don't store classes, they store instances of a class.
Beware of instances that are default constructed without the use of a
default ctor. You'll get surprises.

The celement class should encapsulate your integers and in a case like
this you should keep the integers seperate. Why? Because then you'll
have control over what a default object looks like without having to
initialize the array in its ctor. Use an init list instead.

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

class celement
{
int x, y, z;
public:
celement() : x(0), y(0), z(0) { } // default ctor w init list
celement( int x_, int y_, int z_ ) : x(x_), y(y_), z(z_) { }
~celement() { }
/* friend function */
friend
std::eek:stream& operator<<( std::eek:stream&, const celement& );
};

/* global op<< oveload for celement */
std::eek:stream& operator<<( std::eek:stream& os, const celement& ce )
{
os << "x = " << ce.x;
os << ", y = " << ce.y;
os << ", z = " << ce.z;
return os << std::endl;
}

class vec
{
std::vector< celement > v;
public:
vec() : v() { }
vec(size_t sz) : v(sz) { } // preset size of vector with def
elements
~vec() { }
size_t size() const { return v.size(); }
void push_back( const celement& ce ) { v.push_back( ce ); }
celement& operator[]( unsigned index ) { return v[index]; }
};

int main()
{
vec container(5);
container.push_back( celement(10,11,12) );
std::cout << "container's size = " << container.size();
std::cout << std::endl;

for ( size_t i = 0; i < container.size(); ++i)
{
std::cout << "container[ " << i << " ] ";
std::cout << container[ i ];
}
return 0;
}

/*
container's size = 6
container[ 0 ] x = 0, y = 0, z = 0
container[ 1 ] x = 0, y = 0, z = 0
container[ 2 ] x = 0, y = 0, z = 0
container[ 3 ] x = 0, y = 0, z = 0
container[ 4 ] x = 0, y = 0, z = 0
container[ 5 ] x = 10, y = 11, z = 12
*/

I'm ignoring the need that celement should have and assignment op for
now.
 
I

imutate

Salt_Peter said:
std::vectors don't store classes, they store instances of a class.

OK, my bad wording.
Beware of instances that are default constructed without the use of a
default ctor. You'll get surprises.

Do you mean I have to provide a constructor ?
Even if I assigned afterwards it could cause problems ?

celement c;
vec.push_back(c);
... later c out of scope
vec.rbegin() -> x[0] = 10;
class vec
{
std::vector< celement > v;
public:
vec() : v() { }
vec(size_t sz) : v(sz) { } // preset size of vector with def
elements
~vec() { }
size_t size() const { return v.size(); }
void push_back( const celement& ce ) { v.push_back( ce ); }
celement& operator[]( unsigned index ) { return v[index]; }
};

Won't you get all these anyway ? Why "present" them to the compiler ?
 
S

Salt_Peter

OK, my bad wording.


Do you mean I have to provide a constructor ?
Even if I assigned afterwards it could cause problems ?

Not neccessarily, but keep in mind that some compilers will default
initialize an integer, for example, to 0 in debug and leave it
unitialized in release mode. Besides, why assign it later when you can
do it at construction time?
celement c;
vec.push_back(c);
.. later c out of scope
vec.rbegin() -> x[0] = 10;

It doesn't matter if c is out of scope, the vector stores an
independant copy of it.
class vec
{
std::vector< celement > v;
public:
vec() : v() { }
vec(size_t sz) : v(sz) { } // preset size of vector with def
elements
~vec() { }
size_t size() const { return v.size(); }
void push_back( const celement& ce ) { v.push_back( ce ); }
celement& operator[]( unsigned index ) { return v[index]; }
};

Won't you get all these anyway ? Why "present" them to the compiler ?

The std::vector is private. The goal is to prevent the user of the
class from directly accessing the components within. As an example, you
can overload vec::push_back(...) to take 3 integer parameters instead
of a celement. You might choose to provide a vec ctor that takes an
array of celements. You could overload a friend operator<< that
iterates through the container seamleassly. The point is that the user
of the class will find it harder to break the container if you protect
its internals.

class vec
{
std::vector< celement > v;
public:
vec() : v() { }
vec(size_t sz) : v(sz) { } // preset size of vector
~vec() { }
size_t size() const { return v.size(); }
void push_back( const celement& ce ) { v.push_back( ce ); }
void push_back( int x, int y, int z ) { v.push_back( celement(x, y,
z) ); }
celement& operator[]( unsigned index ) { return v[index]; }
/* friend function */
friend
std::eek:stream& operator<<( std::eek:stream&, const vec& );
};

std::eek:stream& operator<<( std::eek:stream& os, const vec& r_v )
{
std::cout << "container's size = " << r_v.v.size();
std::cout << std::endl;
typedef std::vector< celement >::const_iterator VIter;
VIter iter = r_v.v.begin();
for ( iter; iter != r_v.v.end(); ++iter )
{
os << *iter;
}
return os;
}

int main()
{
vec container;
celement def;
container.push_back( def );
container.push_back( celement(0, 1, 2) );
container.push_back( 10, 11, 12 );
celement ce( 20, 30, 40 );
container.push_back( ce );
// container.v.clear(); // error: vec::v is private

std::cout << container; // one line for output !!!
return 0;
}

/*
container's size = 4
x = 0, y = 0, z = 0
x = 0, y = 1, z = 2
x = 10, y = 11, z = 12
x = 20, y = 30, z = 40
*/
 
I

imutate

Not neccessarily, but keep in mind that some compilers will default
initialize an integer, for example, to 0 in debug and leave it
unitialized in release mode.

OK, deceptive, but not particularly unusual in computer systems in
general for initialise values to be non 0 or null.
Besides, why assign it later when you can
do it at construction time?

Constructors that assign values make for nice textbook code, but in
practice if you have objects of any complexity you will probably want
to initialise them from disk ( database etc) probably more than once.
So writing constructor code just makes for more work.
The std::vector is private. The goal is to prevent the user of the
class from directly accessing the components within. As an example, you
can overload vec::push_back(...) to take 3 integer parameters instead
of a celement. You might choose to provide a vec ctor that takes an
array of celements.

OK, but why not make a member to "initialise" the object and then call
that from the constructor, that way I don't have to create a new object
just clear it (if neccessary) and call initialise again.

Thanks, for the example.
 
S

Salt_Peter

OK, deceptive, but not particularly unusual in computer systems in
general for initialise values to be non 0 or null.

Note that released, optimized code does not initialize at all unless
the ctor does some sort of default construction. Uninitialized objects
are dangerous since the residual bits that are contained in the object
are used if the instance is operated on. That, in essence, is a common
bug.

Doesn't the compiler have to generate a ctor anyway? Same with copy
ctor, d~tor, etc. Why not take control of what the compiler does?
Consider a class that stores a pointer that is left unitialized by
mistake.
What if you wrote the class's ctor to default initialize the pointer to
0 instead?
The moment you, me or an unsuspecting user of the class makes the
mistake of using an instance of P without setting it: the compiler
generates an error that instantly and precisely diagnoses the problem
(null pointer exception). In the long run, its less work cause you
don't have to split your brains looking for the hard to find bugs. Its
safety built-in to the design. And your clients will love you for it.
Constructors that assign values make for nice textbook code, but in
practice if you have objects of any complexity you will probably want
to initialise them from disk ( database etc) probably more than once.
So writing constructor code just makes for more work.

The ctor is invoked when reading the data from disk directly. In other
words, when the std::ifstream opens the file: it's contents are
seamlessly used to construct (or even reinitialize) the object or its
elements.
OK, but why not make a member to "initialise" the object and then call
that from the constructor, that way I don't have to create a new object
just clear it (if neccessary) and call initialise again.

There is no reason why not. Using some init() member function is
perfectly safe. Which brings us to the core of the issue. The ctor
already supports the init list. I can think of several languages who
would DIE to have the benefits of the init list.

class N
{
int n; // n could be a complex user-type instead
public:
N() : n( initialize() ) { } // perfectly legal
~N() { }
int initialize() const { return 100; } // or whatever is required
};

That way, you can reserve the body of the ctor (and d~tor) for usefull
diagnostics when you are developing the project. as in:

N::N() : n( initialize() ) { std::cout << "N()\n"; }
N::~N() { std::cout << "~N()\n"; }

Which may look trivial at this point but very handy when dealing with
polymorphism and deallocations (you know... memory leaks).
Thanks, for the example.

Your welcome, and give yourself some credits. You at least showed some
code.
 
I

imutate

Salt_Peter said:
Note that released, optimized code does not initialize at all unless
the ctor does some sort of default construction. Uninitialized objects
are dangerous since the residual bits that are contained in the object
are used if the instance is operated on. That, in essence, is a common
bug.

OK. But are you saying that even if I set every variable then there
could be some circumstance where it gets corrupted because of no
implemented ctor ?
Doesn't the compiler have to generate a ctor anyway? Same with copy
ctor, d~tor, etc. Why not take control of what the compiler does?
Consider a class that stores a pointer that is left unitialized by
mistake.
What if you wrote the class's ctor to default initialize the pointer to
0 instead?
The moment you, me or an unsuspecting user of the class makes the
mistake of using an instance of P without setting it: the compiler
generates an error that instantly and precisely diagnoses the problem
(null pointer exception). In the long run, its less work cause you
don't have to split your brains looking for the hard to find bugs. Its
safety built-in to the design. And your clients will love you for it.

Yep, default values are great on interfaces.
The ctor is invoked when reading the data from disk directly. In other
words, when the std::ifstream opens the file: it's contents are
seamlessly used to construct (or even reinitialize) the object or its
elements.

I did not know that. I will read up about ifstream.
There is no reason why not. Using some init() member function is
<snip>

OK I saw some pitfalls in the C++ faq about one ctor calling another,
but this way will avoid those.
Your welcome, and give yourself some credits. You at least showed some
code.

Here is some more, not mine but from supposedly from Stroustrup.
I was wondering you could wrap up std::vector in a similar way..

template < typename T, int max >
struct c_array
{
typedef T value_type;
typedef T* iterator;
typedef const T* const_iterator;
typedef T& reference;
typedef const T& const_reference;
T v[max];


....
google "c_array template c++ Stroustrup" to see the rest.
 

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

No members online now.

Forum statistics

Threads
474,433
Messages
2,571,683
Members
48,796
Latest member
Greg L.

Latest Threads

Top