469,945 Members | 2,280 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,945 developers. It's quick & easy.

std::list and a composite type ..

Consider:

# include <iostream>
using std::cout;
using std::cin;
using std::endl;

# include <list>
using std::list;

struct my_struct
{
std::string mName;
int mValue;
};

typedef std::list<my_struct> my_list;

int main()
{

my_list cc;
my_struct s;
s.mName = "Foo";
s.mValue = 42;
cc.push_back(s); // add contents

s.mName = "Bar";
s.mValue = 67;
cc.push_back(s); // add contents

my_list::iterator it(cc.begin());
for (; it != cc.end(); ++it)
{
cout << "Name = " << (*it).mName.c_str()
<< " Value = " << (*it).mValue << endl;
}

it = cc.begin();
for (; it != cc.end(); ++it)
{
if (it->mName == "Foo")
{
//cout << "found " << '\n';
//cc.erase(it); // exception. How do I erase "Foo"??
}
}

//my_struct* ptr = *it;

my_struct* ptr = new my_struct;
if (!ptr)
std::cerr << "memory allocation failure " << '\n';
it = cc.begin();
for (; it != cc.end(); ++it)
//ptr = it // assign contents of iterator to memory?

delete ptr;
}

The standard list container my_list holds a composite type my_struct.
At issue is the need to 'erase' Foo and it's corresponding value of
42. How do I achieve this?

ptr is a block of memory that's been allocated the sizeof my_struct.
Is it possible to 'assign' the contents of the iterator to that
memory? Silly though this may seem, a classmate/lab partner was
opting to do as such and I informed him. 1. Doesn't make sense and
2. I don't think that can be done.
Jul 22 '05 #1
8 2645
On 20 Jul 2004 10:41:15 -0700, ma740988 <ma******@pegasus.cc.ucf.edu>
wrote:
Consider:

# include <iostream>
using std::cout;
using std::cin;
using std::endl;

# include <list>
using std::list;

struct my_struct
{
std::string mName;
int mValue;
};

typedef std::list<my_struct> my_list;

int main()
{

my_list cc;
my_struct s;
s.mName = "Foo";
s.mValue = 42;
cc.push_back(s); // add contents

s.mName = "Bar";
s.mValue = 67;
cc.push_back(s); // add contents

my_list::iterator it(cc.begin());
for (; it != cc.end(); ++it)
{
cout << "Name = " << (*it).mName.c_str()
<< " Value = " << (*it).mValue << endl;
}

it = cc.begin();
for (; it != cc.end(); ++it)
{
if (it->mName == "Foo")
{
//cout << "found " << '\n';
//cc.erase(it); // exception. How do I erase "Foo"??
}
}

//my_struct* ptr = *it;

my_struct* ptr = new my_struct;
if (!ptr)
std::cerr << "memory allocation failure " << '\n';
it = cc.begin();
for (; it != cc.end(); ++it)
//ptr = it // assign contents of iterator to memory?

delete ptr;
}

The standard list container my_list holds a composite type my_struct.
At issue is the need to 'erase' Foo and it's corresponding value of
42. How do I achieve this?
Same way as you would erase anything from a list.

ptr is a block of memory that's been allocated the sizeof my_struct.
Is it possible to 'assign' the contents of the iterator to that
memory? Silly though this may seem, a classmate/lab partner was
opting to do as such and I informed him. 1. Doesn't make sense and
2. I don't think that can be done.


Yes it's possible (why you would want to do it is another matter) but

*ptr = *it;

The mistake you made in deleting from a list is not what you thought. Look
at the code again.

it = cc.begin();
for (; it != cc.end(); ++it)
{
if (it->mName == "Foo")
{
cout << "found " << '\n';
cc.erase(it); // exception. How do I erase "Foo"??
}
}

The erase is fine, that works, but what is the very next thing that
happens?

Answer

++it

When you erase something from a list (or anything else) using an iterator
you invalidate that iterator. You cannot use that iterator afterwards for
anything else.

Here is how you should have written the code

it = cc.begin();
while (it != cc.end())
{
if (it->mName == "Foo")
{
cout << "found " << '\n';
it = cc.erase(it);
}
else
{
++it;
}
}

list::erase returns an iterator to the next position.

john
Jul 22 '05 #2
[...]

ptr is a block of memory that's been allocated the sizeof my_struct.
Is it possible to 'assign' the contents of the iterator to that
memory? Silly though this may seem, a classmate/lab partner was
opting to do as such and I informed him. 1. Doesn't make sense and
2. I don't think that can be done.
Yes it's possible (why you would want to do it is another matter) but

*ptr = *it;


There's no correlation between the sizeof the memory allocated by new
and the length/memory block of the iterator? In other words, assume
we added(push_back's) some very large number of my_struct's to the
list.
Now I'd envision that care should be taken when assigning the contents
of the iterator to the memory allocated by new, since 'the large
number' of contents may not fit. Yes/No?


The mistake you made in deleting from a list is not what you thought. Look
at the code again.

it = cc.begin();
for (; it != cc.end(); ++it)
{
if (it->mName == "Foo")
{
cout << "found " << '\n';
cc.erase(it); // exception. How do I erase "Foo"??
}
}

The erase is fine, that works, but what is the very next thing that
happens?

Answer

++it

When you erase something from a list (or anything else) using an iterator
you invalidate that iterator. You cannot use that iterator afterwards for
anything else.


I overlooked this.

Thanks
Mark
Jul 22 '05 #3
On 20 Jul 2004 18:57:34 -0700, ma740988 <ma******@pegasus.cc.ucf.edu>
wrote:
[...]
>
> ptr is a block of memory that's been allocated the sizeof my_struct.
> Is it possible to 'assign' the contents of the iterator to that
> memory? Silly though this may seem, a classmate/lab partner was
> opting to do as such and I informed him. 1. Doesn't make sense and
> 2. I don't think that can be done.
Yes it's possible (why you would want to do it is another matter) but

*ptr = *it;


There's no correlation between the sizeof the memory allocated by new
and the length/memory block of the iterator? In other words, assume
we added(push_back's) some very large number of my_struct's to the
list.
Now I'd envision that care should be taken when assigning the contents
of the iterator to the memory allocated by new, since 'the large
number' of contents may not fit. Yes/No?


No. An iterator refers to a *single* item that has been added to the list,
and *it returns a reference to that single item. The number of items in
the list is irrelevant.

This is a new misunderstanding of iterators to me, so I not sure quite
what you are thinking, but clearly you've got some serious misconception
about what iterators are.


The mistake you made in deleting from a list is not what you thought.
Look
at the code again.

it = cc.begin();
for (; it != cc.end(); ++it)
{
if (it->mName == "Foo")
{
cout << "found " << '\n';
cc.erase(it); // exception. How do I erase "Foo"??
}
}

The erase is fine, that works, but what is the very next thing that
happens?

Answer

++it

When you erase something from a list (or anything else) using an
iterator
you invalidate that iterator. You cannot use that iterator afterwards
for
anything else.


Actually my statement is inaccurate. What happens is that when an item is
erased from an list, by any means, all iterators that refer to the erased
item become invalid. Iterators that refer to unerased items remain valid.

john
Jul 22 '05 #4
On Wed, 21 Jul 2004 06:59:27 +0100, John Harrison
<jo*************@hotmail.com> wrote:
On 20 Jul 2004 18:57:34 -0700, ma740988 <ma******@pegasus.cc.ucf.edu>
wrote:
[...]
>
> ptr is a block of memory that's been allocated the sizeof my_struct.
> Is it possible to 'assign' the contents of the iterator to that
> memory? Silly though this may seem, a classmate/lab partner was
> opting to do as such and I informed him. 1. Doesn't make sense and
> 2. I don't think that can be done.


Perhaps you meant the contents of the list, not the contents of the
iterator. Then your objection would make more sense (but still not be
valid).

#include <algorithm>

my_struct* ptr = new my_struct[cc.size()]; // enough room for the entire
list
std::copy(cc.begin(), cc.end(), ptr); // copy entire list to ptr

john
Jul 22 '05 #5
"John Harrison" <jo*************@hotmail.com> wrote in message news:<opsbg4srtd212331@andronicus>...
[...]
Perhaps you meant the contents of the list, not the contents of the
iterator. Then your objection would make more sense (but still not be
valid).
'contents of the list'. Thats correct. I tend to mix up C++
terminology quite often.
#include <algorithm>

my_struct* ptr = new my_struct[cc.size()]; // enough room for the entire
list
std::copy(cc.begin(), cc.end(), ptr); // copy entire list to ptr

Ah!! cc.size() is what I was missing. I knew there had to be a
connection between the size of the memory allocated and the size of
the list to be copied.
The previous version (ie. my_struct* ptr = new my_struct;) could lead
to problems.

One other question.
I recalled reading about the preferred use of std::fill to memset.
One of the prime arguments against memset - as i understood it -
revolved around memset limitation with respect to alignment on byte
boundaries.

For starters std::fill is memset under the hood when viewed from
Visual Studio 7 compiler. Secondly, how would I (couldn't find within
my text and online) std::fill a struct to - say 0.
So now.

struct my_struct
{
std::string mName;
int mValue1;
int mValue2;
};

typedef std::list<my_struct> my_list;

int main()
{
my_struct s;
/// try passing the address of the struct
//std::fill(&s, sizeof s, 0);
my_list cc;
/// try iterators
//std::fill(cc.begin(), cc.end(), 0);
memset (&s, 0, sizeof s);
cout << s.mName.c_str() << '\n';
cout << s.mValue1 << '\n';
cout << s.mValue2 << '\n';
}
Jul 22 '05 #6
On 21 Jul 2004 11:57:21 -0700, ma740988 <ma******@pegasus.cc.ucf.edu>
wrote:

One other question.
I recalled reading about the preferred use of std::fill to memset.
One of the prime arguments against memset - as i understood it -
revolved around memset limitation with respect to alignment on byte
boundaries.

For starters std::fill is memset under the hood when viewed from
Visual Studio 7 compiler.
That's not true in general, it might be true for particular types.
Secondly, how would I (couldn't find within
my text and online) std::fill a struct to - say 0.
So now.

struct my_struct
{
std::string mName;
int mValue1;
int mValue2;
};
That struct cannot be filled to 0 because it contains a std::string. It's
just not a meaningful thing to try and do. What do you think the value of
mName should be after you've filled it with 0?

Further std::fill is for sequences and arrays, it is not for individual
objects.


typedef std::list<my_struct> my_list;

int main()
{
my_struct s;
/// try passing the address of the struct
//std::fill(&s, sizeof s, 0);
my_list cc;
/// try iterators
//std::fill(cc.begin(), cc.end(), 0);
memset (&s, 0, sizeof s);
cout << s.mName.c_str() << '\n';
cout << s.mValue1 << '\n';
cout << s.mValue2 << '\n';
}


You are just getting undefined behaviour here. You cannot memset a string.

The C++ way of doing what I think you are trying to do is to use a
constructor.

struct my_struct
{
my_struct() : mValue1(0), mValue2(0) {}
std::string mName;
int mValue1;
int mValue2;
};

int main()
{
my_struct s;
cout << s.mName << '\n'; // prints empty line
cout << s.mValue1 << '\n'; // prints 0
cout << s.mValue2 << '\n'; // prints 0
}

The constructor ensures that every my_struct has defined values when it is
created.

john
Jul 22 '05 #7
"John Harrison" <jo*************@hotmail.com> wrote in message news:<opsbh4zyvz212331@andronicus>...

[snip]
struct my_struct
{
std::string mName;
int mValue1;
int mValue2;
};


That struct cannot be filled to 0 because it contains a std::string. It's
just not a meaningful thing to try and do. What do you think the value of
mName should be after you've filled it with 0?


Does this mean that you cannot

my_struct s = {0}; // works?

/david
Jul 22 '05 #8
On 21 Jul 2004 18:49:50 -0700, David Rubin <da********@warpmail.net> wrote:
"John Harrison" <jo*************@hotmail.com> wrote in message
news:<opsbh4zyvz212331@andronicus>...

[snip]
> struct my_struct
> {
> std::string mName;
> int mValue1;
> int mValue2;
> };


That struct cannot be filled to 0 because it contains a std::string.
It's
just not a meaningful thing to try and do. What do you think the value
of
mName should be after you've filled it with 0?


Does this mean that you cannot

my_struct s = {0}; // works?

/david


You can do it, and it will compile, but it results in a call to the
std::string constructor with a NULL pointer, which is undefined behaviour
as I recall.

You could do this

my_struct s = { "" };

john
Jul 22 '05 #9

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

14 posts views Thread by Dave | last post: by
8 posts views Thread by JustSomeGuy | last post: by
7 posts views Thread by alex221 | last post: by
7 posts views Thread by TBass | last post: by
12 posts views Thread by isliguezze | last post: by
11 posts views Thread by Juha Nieminen | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.