Hello,
I'm quite new to C++ so maybe there's something I miss.
I write a simple board game. It has a board class. This class has a
method that returns the count of pieces a player has on the board. Since
this function does not change anything in the class I declared it as
const. To count all pieces of a given color the functions iterates
through a "map" of CNode-pointers. "CNode" is another class that is
irrelevant to the problem.
Here comes the function: (EColor is an enum of colors, not important here)
int
CBoard::countPieces(EColor color) const
{
// "nodes" is a private class member
// with type map<string,CNode*>
int count = 0;
for (map<string,CNode*>::iterator i=nodes.begin();
i != nodes.end();
i++)
{
// do something with (*i)
// ...
}
return count;
}
The compiler refuses to compile the code, because I violate the
constness of the function in the line where I declare the iterator.
Is there a proper way (or workaround) to leave the function const?
Another point: I've heard, that it is not good to store pointers to
objects in stl-containers like map, list, vector etc. because of
ownership problems (?). Do you know a good webpage or tutorial about
this topic? I would like to learn how to do it the right way.
There are a lot of classes in the STL and I would like to know how to
use their whole power. At the moment I'm just using lists, vectors and
maps in lack of a good book or online tutorial discussing the STL in detail.
Thanks in advance!
--
Regards,
Christof Krueger
Remove "donotspam" if you want to email me. 12 1896
In article <bu*************@news.t-online.com>, Christof Krueger wrote: Hello,
I'm quite new to C++ so maybe there's something I miss. I write a simple board game. It has a board class. This class has a method that returns the count of pieces a player has on the board. Since this function does not change anything in the class I declared it as const. To count all pieces of a given color the functions iterates through a "map" of CNode-pointers. "CNode" is another class that is irrelevant to the problem.
Here comes the function: (EColor is an enum of colors, not important here)
int CBoard::countPieces(EColor color) const { // "nodes" is a private class member // with type map<string,CNode*> int count = 0; for (map<string,CNode*>::iterator i=nodes.begin(); i != nodes.end(); i++) { // do something with (*i) // ... } return count; }
The compiler refuses to compile the code, because I violate the constness of the function in the line where I declare the iterator. Is there a proper way (or workaround) to leave the function const?
map<string,CNode*>::const_iterator
btw, you can do this using
count_if(themap.begin(),themap.end(),isWhite); // isWhite returns true if the piece is white
Another point: I've heard, that it is not good to store pointers to objects in stl-containers like map, list, vector etc. because of ownership problems (?).
It's not necessarily a bad thing. But you need to make sure that you understand
who "owns" a given pointer, and you need to make sure that the map doesn't hold
on to "dead pointers".
Here's my question: how are your pointers allocated and deleted ? Who owns them ?
Do you know a good webpage or tutorial about this topic? I would like to learn how to do it the right way.
This topic is too complicated to be discussed exhaustively in "a webpage". You
need to read a couple of good books that deal with memory management issues.
There are a lot of classes in the STL and I would like to know how to use their whole power. At the moment I'm just using lists, vectors and maps in lack of a good book or online tutorial discussing the STL in detail.
Two good books about the C++ standard library:
"Accelerated C++" Koenig and Moo
"The Standard C++ Library A Tutorial and a Reference" Josuttis
Cheers,
--
Donovan Rebbechi http://pegasus.rutgers.edu/~elflord/
Christof Krueger wrote: Hello,
I'm quite new to C++ so maybe there's something I miss. I write a simple board game. It has a board class. This class has a method that returns the count of pieces a player has on the board. Since this function does not change anything in the class I declared it as const. To count all pieces of a given color the functions iterates through a "map" of CNode-pointers. "CNode" is another class that is irrelevant to the problem.
Here comes the function: (EColor is an enum of colors, not important here)
int CBoard::countPieces(EColor color) const { // "nodes" is a private class member // with type map<string,CNode*> int count = 0; for (map<string,CNode*>::iterator i=nodes.begin(); i != nodes.end(); i++) { // do something with (*i) // ... } return count; }
The compiler refuses to compile the code, because I violate the constness of the function in the line where I declare the iterator. Is there a proper way (or workaround) to leave the function const?
Another point: I've heard, that it is not good to store pointers to objects in stl-containers like map, list, vector etc. because of ownership problems (?). Do you know a good webpage or tutorial about this topic? I would like to learn how to do it the right way. There are a lot of classes in the STL and I would like to know how to use their whole power. At the moment I'm just using lists, vectors and maps in lack of a good book or online tutorial discussing the STL in detail.
Thanks in advance!
use const_iterator.
for (map<string,CNode*>::const_iterator i = nodes.begin(); ...
Also, you should use ++i instead of i++, for reasons of style and
efficiency (no need to copy the "old" state of the iterator).
You might also want to look into using std::for_each()
e.g.:
class my_counter : public std::unary_function<
std::pair<string,CNode*>,
void >
{
private:
mutable int count;
public:
my_counter() : count(0) { }
void operator()(const std::pair<string,CNode*>& val) const
{
// do something here that manipulates count
}
int get_count() const { return count; }
};
int CBoard::countPieces(EColor color)
{
return std::for_each(nodes.begin(),
nodes.end(),
my_counter()).get_count();
}
Christof Krueger wrote in news:bu*************@news.t-online.com:
[snip] int CBoard::countPieces(EColor color) const { // "nodes" is a private class member // with type map<string,CNode*> int count = 0; for (map<string,CNode*>::iterator i=nodes.begin();
for ( map<string,CNode*>::const_iterator i=nodes.begin();
i != nodes.end(); i++) { // do something with (*i) // ... } return count; }
The compiler refuses to compile the code, because I violate the constness of the function in the line where I declare the iterator. Is there a proper way (or workaround) to leave the function const?
Your problem is that when you call nodes.begin() your calling
the const version that returns a const_iterator. a const_iterator
like a pointer to a const doesn't allow you to modify the item
that its iterating (pointing) to. Another point: I've heard, that it is not good to store pointers to objects in stl-containers like map, list, vector etc. because of ownership problems (?).
Look into smart pointers, in particular boost::shared_ptr: http://www.boost.org/libs/smart_ptr/shared_ptr.htm
Do you know a good webpage or tutorial about this topic? I would like to learn how to do it the right way. There are a lot of classes in the STL and I would like to know how to use their whole power. At the moment I'm just using lists, vectors and maps in lack of a good book or online tutorial discussing the STL in detail.
No, mostly people around hear recomend geting a good book.
Accelerated C++ (Koenig & moo) is most recomended book for this.
Rob.
-- http://www.victim-prime.dsl.pipex.com/
Donovan Rebbechi wrote: In article <bu*************@news.t-online.com>, Christof Krueger wrote:
Hello,
I'm quite new to C++ so maybe there's something I miss. I write a simple board game. It has a board class. This class has a method that returns the count of pieces a player has on the board. Since this function does not change anything in the class I declared it as const. To count all pieces of a given color the functions iterates through a "map" of CNode-pointers. "CNode" is another class that is irrelevant to the problem.
Here comes the function: (EColor is an enum of colors, not important here)
int CBoard::countPieces(EColor color) const { // "nodes" is a private class member // with type map<string,CNode*> int count = 0; for (map<string,CNode*>::iterator i=nodes.begin(); i != nodes.end(); i++) { // do something with (*i) // ... } return count; }
The compiler refuses to compile the code, because I violate the constness of the function in the line where I declare the iterator. Is there a proper way (or workaround) to leave the function const?
map<string,CNode*>::const_iterator
thanks, that makes sense :)
btw, you can do this using
count_if(themap.begin(),themap.end(),isWhite); // isWhite returns true if the piece is white
very handy. I'll use it. Another point: I've heard, that it is not good to store pointers to objects in stl-containers like map, list, vector etc. because of ownership problems (?).
It's not necessarily a bad thing. But you need to make sure that you understand who "owns" a given pointer, and you need to make sure that the map doesn't hold on to "dead pointers".
Here's my question: how are your pointers allocated and deleted ? Who owns them ?
In this case the board creates the nodes, stores them in the map and
deletes them in it's destructor. I see that ownership is a question of
design. Thanks! Do you know a good webpage or tutorial about this topic? I would like to learn how to do it the right way.
This topic is too complicated to be discussed exhaustively in "a webpage". You need to read a couple of good books that deal with memory management issues.
There are a lot of classes in the STL and I would like to know how to use their whole power. At the moment I'm just using lists, vectors and maps in lack of a good book or online tutorial discussing the STL in detail.
Two good books about the C++ standard library:
"Accelerated C++" Koenig and Moo "The Standard C++ Library A Tutorial and a Reference" Josuttis
I'll take a look on Josuttis book.
Another question:
If I had a public method getNodeMap() that should return my nodes-map to
the caller, is there a possibility to make this method const and to
return a const version of the map, so that the caller may not change the
returned map? I tried that once, but failed because of a lot of compiler
errors.
--
Regards,
Christof Krueger
Remove "donotspam" if you want to email me.
red floyd wrote: Christof Krueger wrote:
Hello,
I'm quite new to C++ so maybe there's something I miss. I write a simple board game. It has a board class. This class has a method that returns the count of pieces a player has on the board. Since this function does not change anything in the class I declared it as const. To count all pieces of a given color the functions iterates through a "map" of CNode-pointers. "CNode" is another class that is irrelevant to the problem.
Here comes the function: (EColor is an enum of colors, not important here)
int CBoard::countPieces(EColor color) const { // "nodes" is a private class member // with type map<string,CNode*> int count = 0; for (map<string,CNode*>::iterator i=nodes.begin(); i != nodes.end(); i++) { // do something with (*i) // ... } return count; }
The compiler refuses to compile the code, because I violate the constness of the function in the line where I declare the iterator. Is there a proper way (or workaround) to leave the function const?
Another point: I've heard, that it is not good to store pointers to objects in stl-containers like map, list, vector etc. because of ownership problems (?). Do you know a good webpage or tutorial about this topic? I would like to learn how to do it the right way. There are a lot of classes in the STL and I would like to know how to use their whole power. At the moment I'm just using lists, vectors and maps in lack of a good book or online tutorial discussing the STL in detail.
Thanks in advance!
use const_iterator.
for (map<string,CNode*>::const_iterator i = nodes.begin(); ...
Also, you should use ++i instead of i++, for reasons of style and efficiency (no need to copy the "old" state of the iterator).
I always thought that i++ is equivalent to ++i in a for loop. Could you
give more detail what the difference is since I do not understand what
you mean by saying "no need to copy the "old" state of the iterator".
Are there cases where it would be nessecary to use i++ though? You might also want to look into using std::for_each()
e.g.:
class my_counter : public std::unary_function< std::pair<string,CNode*>, void > { private: mutable int count; public: my_counter() : count(0) { } void operator()(const std::pair<string,CNode*>& val) const { // do something here that manipulates count } int get_count() const { return count; } }; int CBoard::countPieces(EColor color) { return std::for_each(nodes.begin(), nodes.end(), my_counter()).get_count(); }
I don't understand why std::for_each(...) returns a my_counter object in
this case. Could you explain it to me pleas (or just give me a hint so I
can look it up myself)?
--
Regards,
Christof Krueger
Remove "donotspam" if you want to email me.
In article <bu*************@news.t-online.com>, Christof Krueger wrote: Donovan Rebbechi wrote:
It's not necessarily a bad thing. But you need to make sure that you understand who "owns" a given pointer, and you need to make sure that the map doesn't hold on to "dead pointers".
Here's my question: how are your pointers allocated and deleted ? Who owns them ? In this case the board creates the nodes, stores them in the map and deletes them in it's destructor. I see that ownership is a question of design. Thanks!
I see.
But why not instead store the node in an automatic structure:
class Handle
{
Node* impl;
public:
Handle(Node* x):impl(x) {}
/*
how you "handle" these is up to you ...
Handle (const Handle& );
Handle& operator= (const Handle&);
*/
~Handle() { delete impl; }
Node& operator*() { return *impl; }
const Node& operator*() const { return *impl; }
Node* operator->(){ return impl; }
const Node* operator->() const { return impl; }
};
Another question: If I had a public method getNodeMap() that should return my nodes-map to the caller, is there a possibility to make this method const and to return a const version of the map,
You could make the function return a const reference to the map. But that's
a bad idea because it reveals implementation details.
A better approach would be to have begin() and end() methods that return
const_iterators and use a typedef to make it looks as though the map iterators
"belong" to the board class.
e.g.
class Board
{
std::map<foo,bar> m;
public:
typedef std::map< foo, bar>::const_iterator const_iterator;
const_iterator begin() const { return m.begin(); }
const_iterator end() const { return m.end(); }
Cheers,
--
Donovan Rebbechi http://pegasus.rutgers.edu/~elflord/
In article <bu*************@news.t-online.com>, Christof Krueger wrote: I don't understand why std::for_each(...) returns a my_counter object in this case.
It does in case you want to do a post-mortem on the state of the object, as
he shows.
However, storing state in function objects like this is a hideous abomination
which can cause all kinds of subtle errors [ see Herb Sutter: More Exceptional C++).
I'd recommend steering clear of this. "red_floyd" is either a troll, or knows
just enough to be really dangerous.
Cheers,
--
Donovan Rebbechi http://pegasus.rutgers.edu/~elflord/
Donovan Rebbechi wrote: But why not instead store the node in an automatic structure:
class Handle { Node* impl; public: Handle(Node* x):impl(x) {} /* how you "handle" these is up to you ... Handle (const Handle& ); Handle& operator= (const Handle&); */ ~Handle() { delete impl; } Node& operator*() { return *impl; } const Node& operator*() const { return *impl; } Node* operator->(){ return impl; } const Node* operator->() const { return impl; } };
Why not just use a std::auto_ptr?
--
Andrew
In article <CijQb.241071$JQ1.135987@pd7tw1no>, Andrew Taylor wrote: Donovan Rebbechi wrote:
But why not instead store the node in an automatic structure:
class Handle { Node* impl; public: Handle(Node* x):impl(x) {} /* how you "handle" these is up to you ... Handle (const Handle& ); Handle& operator= (const Handle&); */ ~Handle() { delete impl; } Node& operator*() { return *impl; } const Node& operator*() const { return *impl; } Node* operator->(){ return impl; } const Node* operator->() const { return impl; } };
Why not just use a std::auto_ptr?
Because he's storing it in a std::map. auto_ptr doesn't play nice with
standard containers because copy construct and copy-assign modify their
arguments.
For example, this doesn't compile:
std::map<int, std::auto_ptr<int> > m;
std::map<int, std::auto_ptr<int> > n(m);
To "play nice" with containers, you'd a smart pointer that had non-modifying
copy operations (like a reference counted pointer, or a deep-copy pointer)
Cheers,
--
Donovan Rebbechi http://pegasus.rutgers.edu/~elflord/
Donovan Rebbechi wrote: In article <bu*************@news.t-online.com>, Christof Krueger wrote:
I don't understand why std::for_each(...) returns a my_counter object in this case.
It does in case you want to do a post-mortem on the state of the object, as he shows.
However, storing state in function objects like this is a hideous abomination which can cause all kinds of subtle errors [ see Herb Sutter: More Exceptional C++). I'd recommend steering clear of this. [snip]
Not having said source at hand, might you elaborate (or at least sketch)?
Many thanks,
-ag
--
Artie Gold -- Austin, Texas
In article <bu************@ID-219787.news.uni-berlin.de>, Artie Gold wrote: Donovan Rebbechi wrote: In article <bu*************@news.t-online.com>, Christof Krueger wrote:
I don't understand why std::for_each(...) returns a my_counter object in this case.
It does in case you want to do a post-mortem on the state of the object, as he shows.
However, storing state in function objects like this is a hideous abomination which can cause all kinds of subtle errors [ see Herb Sutter: More Exceptional C++). I'd recommend steering clear of this. [snip]
Not having said source at hand, might you elaborate (or at least sketch)?
Many algorithms copy their predicates. The order of application is often
specified.
I'm going to offer a sketch that's relevant to this example.
for_each "should" behave sensibly, one would hope, from reading the standard:
Effects: Applies f to the result of dereferencing every iterator in the
range [first, last) starting from first and proceeding to last - 1
Returns: f
Complexity: applies f exactly last - first times.
Great! So what does this code do ?
template <typename T>
struct counter
{
int val;
counter () : val(0){}
void operator()(T& x) { ++val; }
};
int main()
{
std::vector<int> v;
v.resize(20);
counter<int> a;
std::cout << std::for_each(v.begin(),v.end(),counter<int>() ).val
<< std::endl;
std::cout << a.val << std::endl; // surely this is the same, right ?
}
The problem is that for_each takes a value parameter, so it operates on a
copy of 'a', not on 'a' itself. This is why for_each returns the predicate.
So there's nothing strictly "incorrect" about "red_floyd's" code, though
count_if is really much simpler. Philosophically, however, it's problematic
because it forces you to depend on side effects, which in turn forces you to
worry about the details of the loop mechanics -- which is precisely the sort
of thing that functional programming is supposed to abstract away.
BTW, in circumstances where some sort of "running total" is required, one can
use the accumulate algorithm (it's quite easy to write a counter function
object that you can use with accumulate in this example) It's a cleaner
solution in that it doesn't burden your function object with state information.
struct counter2
{
template <typename T>
int operator() (int x, const T&) { return x+1; }
};
accumulate(x.begin(),x.end(),0,counter2());
Cheers,
--
Donovan Rebbechi http://pegasus.rutgers.edu/~elflord/
Donovan Rebbechi wrote: In article <bu************@ID-219787.news.uni-berlin.de>, Artie Gold wrote:
Donovan Rebbechi wrote:
In article <bu*************@news.t-online.com>, Christof Krueger wrote:
I don't understand why std::for_each(...) returns a my_counter object in this case.
It does in case you want to do a post-mortem on the state of the object, as he shows.
However, storing state in function objects like this is a hideous abomination which can cause all kinds of subtle errors [ see Herb Sutter: More Exceptional C++). I'd recommend steering clear of this. [snip]
Not having said source at hand, might you elaborate (or at least sketch)?
Many algorithms copy their predicates. The order of application is often specified.
I'm going to offer a sketch that's relevant to this example.
for_each "should" behave sensibly, one would hope, from reading the standard:
Effects: Applies f to the result of dereferencing every iterator in the range [first, last) starting from first and proceeding to last - 1 Returns: f Complexity: applies f exactly last - first times.
Great! So what does this code do ?
template <typename T> struct counter { int val; counter () : val(0){} void operator()(T& x) { ++val; } };
int main() { std::vector<int> v; v.resize(20); counter<int> a; std::cout << std::for_each(v.begin(),v.end(),counter<int>() ).val << std::endl; std::cout << a.val << std::endl; // surely this is the same, right ? }
The problem is that for_each takes a value parameter, so it operates on a copy of 'a', not on 'a' itself. This is why for_each returns the predicate.
So there's nothing strictly "incorrect" about "red_floyd's" code, though count_if is really much simpler. Philosophically, however, it's problematic because it forces you to depend on side effects, which in turn forces you to worry about the details of the loop mechanics -- which is precisely the sort of thing that functional programming is supposed to abstract away.
BTW, in circumstances where some sort of "running total" is required, one can use the accumulate algorithm (it's quite easy to write a counter function object that you can use with accumulate in this example) It's a cleaner solution in that it doesn't burden your function object with state information.
struct counter2 { template <typename T> int operator() (int x, const T&) { return x+1; } };
accumulate(x.begin(),x.end(),0,counter2());
Tremendous!
--ag
--
Artie Gold -- Austin, Texas This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: JustSomeGuy |
last post by:
I need to write an new class derived from the list class.
This class stores data in the list to the disk if an object
that is added to the list is over 1K in size.
What methods of the std stl...
|
by: Random Person |
last post by:
Does anyone know how to use VBA to relink tables between two MS Access
databases? We have two databases, one with VBA code and the other with
data tables. The tables are referenced by linked...
|
by: Colin Anderson |
last post by:
I discovered, with great excitement, this article
http://www.davison.uk.net/vb2notes.asp when researching methods for
emailing from Access via Notes. Unfortunatly, when I run this I get a...
|
by: Grasshopper |
last post by:
Hi,
I am automating Access reports to PDF using PDF Writer 6.0. I've
created a DTS package to run the reports and schedule a job to run this
DTS package. If I PC Anywhere into the server on...
|
by: Daveyk0 |
last post by:
Hello there,
I have a front end database that I have recently made very many changes
to to allow off-line use. I keep copies of the databases on my hard
drive and link to them rather than the...
|
by: ransoma22 |
last post by:
I developing an application that receive SMS from a connected GSM
handphone, e.g Siemens M55, Nokia 6230,etc through the data cable.
The application(VB.NET) will receive the SMS automatically,...
|
by: fakeprogress |
last post by:
For a homework assignment in my Data Structures/C++ class, I have to
create the interface and implementation for a class called Book, create
objects within the class, and process transactions that...
|
by: Homeworkboy |
last post by:
Can anyone help me with this program?
Look at the bottom of this program for help methods:
/*1. Make a program that uses numbers from 1 to 100 including each ends which puts the even...
|
by: Zytan |
last post by:
This returns the following error:
"Cannot modify the return value of
'System.Collections.Generic.List<MyStruct>.this' because it is
not a variable"
and I have no idea why! Do lists return copies...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: BarryA |
last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Sonnysonu |
last post by:
This is the data of csv file
1 2 3
1 2 3
1 2 3
1 2 3
2 3
2 3
3
the lengths should be different i have to store the data by column-wise with in the specific length.
suppose the i have to...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
|
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome a new...
| | |