C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

RAII and STL (perhaps a FAQ?)
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Michael Jørgensen
Guest





PostPosted: Thu Oct 20, 2005 1:59 pm    Post subject: RAII and STL (perhaps a FAQ?) Reply with quote



Say I have a class that represents a resource

class Resource
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.
};

Next, I have a container of such resources, e.g.

std::map< Identifier, Resource > resourceMap;

My problem is now, that the STL (e.g. make_pair() ) calls the copy
constructor of my class Resource. This leads to run-time failure, because
the handle is copied.

If I declare a private copy constructor, the code will not compile.

In order to get the above to work, I must therefore additionally write my
own copy constructor *and* some mechanism like reference counting. This
seems like a lot of work and becomes error-prone.

Am I doing something wrong here? I'm interested in both design issues and
implementation issues.

Should I instead declare my resourceMap with pointers, i.e.

std::map< Identifier, Resource *> resourceMap;
?

Thanks in advance,
-Michael.



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Maciej Sobczak
Guest





PostPosted: Thu Oct 20, 2005 5:27 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote



Michael Jørgensen wrote:

Quote:
Should I instead declare my resourceMap with pointers, i.e.

std::map< Identifier, Resource *> resourceMap;

Better:

std::map<Identifier, boost::shared_ptr resourceMap;

In general, classes that encapsulate external resources are almost never
copyable - they cannot be used with STL directly. On the other hand,
messing with raw pointers is asking for trouble, so some form of smart
pointer is preferable here. Note also that a smart pointer is itself
kind of automatic resource handler - but it is generic so that you don't
have to reinvent the wheel by writing your own reference counting logic.


--
Maciej Sobczak : http://www.msobczak.com/
Programming : http://www.msobczak.com/prog/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Dan McLeran
Guest





PostPosted: Thu Oct 20, 2005 5:28 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote



IMO, the best thing to do would be to have your class inherit
boost::noncopyable and then hold reference-counted pointers to your
class in a map:

class Resource : public boost::noncopyable
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.

};

typedef boost::shared_ptr<Resource> PointerToResourceType;
typedef std::map< Identifier, PointerToResourceType> ResourceMapType;

ResourceMapType resourceMap;

see www.boost.org for docs on boost::noncopyable and shared_ptr

Regards,

Dan McLeran


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
peter koch larsen
Guest





PostPosted: Thu Oct 20, 2005 6:45 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote


Michael Jørgensen skrev:

Quote:
Say I have a class that represents a resource

class Resource
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.
};

Next, I have a container of such resources, e.g.

std::map< Identifier, Resource > resourceMap;

My problem is now, that the STL (e.g. make_pair() ) calls the copy
constructor of my class Resource. This leads to run-time failure, because
the handle is copied.

Right. The standard C++ collections are value-based. Arguably, your
Resource class is bad since it does not handle copying correctly.

Quote:

If I declare a private copy constructor, the code will not compile.

Yup - you've just fixed your class (except for declaring the assignment
operator private to).
Quote:

In order to get the above to work, I must therefore additionally write my
own copy constructor *and* some mechanism like reference counting. This
seems like a lot of work and becomes error-prone.
You could use some standard (or almost standard) class for that - such

as the shared pointer from boost.
Quote:

Am I doing something wrong here? I'm interested in both design issues and
implementation issues.

Should I instead declare my resourceMap with pointers, i.e.

std::map< Identifier, Resource *> resourceMap;
?
This could be okay and is just one step from the shared_ptr from boost.

This class gives you the guaranteed destruction guarantee.
Quote:

Thanks in advance,
-Michael.

/Peter


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
David Abrahams
Guest





PostPosted: Thu Oct 20, 2005 6:47 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote

"Michael Jørgensen" <ccc59035 (AT) vip (DOT) cybercity.dk> writes:

Quote:
Say I have a class that represents a resource

class Resource
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.
};

Next, I have a container of such resources, e.g.

std::map< Identifier, Resource > resourceMap;

My problem is now, that the STL (e.g. make_pair() ) calls the copy
constructor of my class Resource. This leads to run-time failure, because
the handle is copied.

If I declare a private copy constructor, the code will not compile.

In order to get the above to work, I must therefore additionally write my
own copy constructor *and* some mechanism like reference counting. This
seems like a lot of work and becomes error-prone.

Am I doing something wrong here? I'm interested in both design issues and
implementation issues.

You're not doing anything wrong. Until we get formal support for move
semantics (google "rvalue reference site:open-std.org"), that's
probably the best you can do.

HTH,

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Thomas Maeder
Guest





PostPosted: Thu Oct 20, 2005 6:48 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote

"Michael Jørgensen" <ccc59035 (AT) vip (DOT) cybercity.dk> writes:

Quote:
Say I have a class that represents a resource

class Resource
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.
};

Next, I have a container of such resources, e.g.

std::map< Identifier, Resource > resourceMap;

My problem is now, that the STL (e.g. make_pair() ) calls the copy
constructor of my class Resource. This leads to run-time failure, because
the handle is copied.

If I declare a private copy constructor, the code will not compile.

In order to get the above to work, I must therefore additionally write my
own copy constructor *and* some mechanism like reference counting. This
seems like a lot of work and becomes error-prone.

Am I doing something wrong here?

Possibly.

Have you considered using boost::shared_ptr
(cf. [url]http://www.boost.org/)?[/url] The developers of this template have
already seen the possible errors and fixed them.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Mirek Fidler
Guest





PostPosted: Thu Oct 20, 2005 7:33 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote

Quote:
Say I have a class that represents a resource

class Resource
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.
};

In order to get the above to work, I must therefore additionally write my
own copy constructor *and* some mechanism like reference counting. This
seems like a lot of work and becomes error-prone.

Am I doing something wrong here?

No. STL does. Requirement for elements to be copy-constructible and
assignable limits the real usage of STL containers to storing
fundamental types plus perhaps smart pointers (with reduced performance
for later).

There are several motions to resolve this problem. There is proposal for
adding move semantics via "r-value references" to the core language,
originally suggested by Howard Hinnant:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html

Staying within limits of current language and covering much wider set of
issues, you can try to investigate possibilities of my petty project:

http://upp.sourceforge.net/srcdoc-us.html
http://upp.sourceforge.net/srcdoc-us.html
http://upp.sourceforge.net/srcdoc-us.html
http://upp.sourceforge.net/srcdoc-us.html
http://upp.sourceforge.net/srcdoc-us.html

Somewhat similar to some of ideas in my petty-project is Roland
Pibingers ptr_vector_owner (although I believe he has not gone far
enough to fully exploit my Array idea Smile:

http://www.codeproject.com/vcpp/stl/ptr_vecto.asp

Mirek

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
thorsten.ottosen@dezide.c
Guest





PostPosted: Thu Oct 20, 2005 7:35 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote


Michael Jørgensen skrev:

Quote:
Say I have a class that represents a resource

class Resource
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.
};

Next, I have a container of such resources, e.g.

std::map< Identifier, Resource > resourceMap;

My problem is now, that the STL (e.g. make_pair() ) calls the copy
constructor of my class Resource. This leads to run-time failure, because
the handle is copied.

If I declare a private copy constructor, the code will not compile.

In order to get the above to work, I must therefore additionally write my
own copy constructor *and* some mechanism like reference counting. This
seems like a lot of work and becomes error-prone.

Am I doing something wrong here? I'm interested in both design issues and
implementation issues.

Should I instead declare my resourceMap with pointers, i.e.

std::map< Identifier, Resource *> resourceMap;
?

The correct solution is to declare both assignment operator and the cc
private.

Next use a container that doesn't copy elements, preferably

boost::ptr_map<Identifier,Resource> map;

See

http://www.boost.org/libs/ptr_container/doc/ptr_container.html
http://www.boost.org/libs/ptr_container/doc/ptr_map.html

for refrences

br

Thorsten


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Alexis Nikichine
Guest





PostPosted: Thu Oct 20, 2005 7:36 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote

Michael Jørgensen wrote:

Quote:
class Resource
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.
};

Next, I have a container of such resources, e.g.

std::map< Identifier, Resource > resourceMap;


In order to get the above to work, I must therefore additionally write my
own copy constructor *and* some mechanism like reference counting. This
seems like a lot of work and becomes error-prone.

Or you must somehow make the promise that you will not use Resource
anymore, once it is handed on to make_pair.
What you need, really here, is a move constructor: I give you this
object (not by reference, Imean), please copy it lightweightly since I
won't be using it anymore.

The nicest read on the topic I've found is still
http://www.cuj.com/documents/s=8246/cujcexp2102alexandr/

It won't help you much, though, since the whole STL is unaware of this,
including make_pair (and std::vector...)

And, as says the article, "discussions are ravaging the usenet" so, yes,
it must some FAQ :-)

Quote:
Am I doing something wrong here? I'm interested in both design issues and
implementation issues.

Should I instead declare my resourceMap with pointers, i.e.

std::map< Identifier, Resource *> resourceMap;
?

Well, pointers don't mix too well with RAII. One solution, in current
C++, is to wrap all your pointers inside a refcounted smart pointers
such as boost:shared_ptr, so you don't have to do the refcounting
yourself. Or maybe boost:ptr_container has ways for you to go.

Less conveniently, you can make your own, mojo aware, containers.

Regards,

Alexis

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Roland Pibinger
Guest





PostPosted: Fri Oct 21, 2005 8:17 am    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote

On 20 Oct 2005 09:59:59 -0400, "Michael Jørgensen"
<ccc59035 (AT) vip (DOT) cybercity.dk> wrote:

Quote:
Say I have a class that represents a resource

class Resource
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.
};

Next, I have a container of such resources, e.g.

std::map< Identifier, Resource > resourceMap;

My problem is now, that the STL (e.g. make_pair() ) calls the copy
constructor of my class Resource. This leads to run-time failure, because
the handle is copied.

If I declare a private copy constructor, the code will not compile.

In order to get the above to work, I must therefore additionally write my
own copy constructor *and* some mechanism like reference counting. This
seems like a lot of work and becomes error-prone.

Am I doing something wrong here? I'm interested in both design issues and
implementation issues.

Should I instead declare my resourceMap with pointers, i.e.

std::map< Identifier, Resource *> resourceMap;

Define a non-copyable ResouceManager that owns your non-copyable
resources.

class Resource
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.
// non copyable
Resource (const Resource&);
Resource& operator= (const Resource&);
};

class ResourceManager
{
public:
Resource* getResource (key) {
Resource* res;
// ...
if (resourceNotFound) {
Resource* res = new Resource (...);
resourceMap.insert (make_pair (key, res);
}
return res;
}

~ResourceManager() {
std::map< Identifier, Resource *>::iterator iter;
for (iter = resourceMap.begin(); iter != resourceMap.end; ++iter){
// delete all resources
}
}

private:
std::map< Identifier, Resource *> resourceMap;
// non copyable
ResourceManager (const ResourceManager&);
ResourceManager& operator= (const ResourceManager&);
};

This is known as 'Creator as Sole Owner' pattern and, IMO, its the
'Silver Bullet' of resource management in C++.
See also: http://www.artima.com/intv/modern3.html
Also, beware of anything that contains the word 'smart' (e.g. 'smart'
pointers)!

Best wishes,
Roland Pibinger

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Le Chaud Lapin
Guest





PostPosted: Fri Oct 21, 2005 9:14 am    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote


Mirek Fidler wrote:
[snippage]
Quote:
...... Requirement for elements to be copy-constructible and
assignable limits the real usage of STL containers to storing
fundamental types plus perhaps smart pointers (with reduced performance
for later).

I routinely store complex constructs which are themselves composed of
containers of containers of elements without incident.

IMO, it is generally a good idea to see if you can get a class to
behave like a fundamental object, with simple, no-brainer, default
construction, assigment, copy construction, and self destruction. My
gut feeling is that the OP can make his Resource class behave this way
using some type of handle-duplication function provided by the
operating system. If he does this, then he can forget about pointers
and other things, and simply wield the object as he had intended to.

One could summarize this principle as:

Microscopic rigidity leads to macroscopic flexibility.

-Le Chaud Lapin-


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Carl Barron
Guest





PostPosted: Fri Oct 21, 2005 3:54 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote

In article <3rpqqfFkr2p2U1 (AT) individual (DOT) net>, Mirek Fidler <cxl (AT) volny (DOT) cz>
wrote:

Quote:
Say I have a class that represents a resource

class Resource
{
public:
Resource() {/* Allocate resource */}
~Resouce() {/* Free resource */}
private:
int handle; // A handle to the requested resource.
};

In order to get the above to work, I must therefore additionally write my
own copy constructor *and* some mechanism like reference counting. This
seems like a lot of work and becomes error-prone.

Am I doing something wrong here?

No. STL does. Requirement for elements to be copy-constructible and
assignable limits the real usage of STL containers to storing
fundamental types plus perhaps smart pointers (with reduced performance
for later).

class RAII

{
private:
// All ctors are private as is assignment
RAII(){ /* allocate resources */}
RAII(const RAII &);
RAII const & operator = (const RAII &);
struct deleter
{
void operator () (RAII *p)
{
/*deallocate resources of *p here */
}
};
public:
static boost::shared_ptr<RAII> create()
{
return boost::shared_ptr<RAII>(new RAII(),deleter());
}
};

NB only shared_ptr<RAII>'s can be created this way,RAII's can;t
be copied either.
store boost::shared_ptr<RAII>'s in your container. As soon as the
last reference to an RAII is destroyed, the deallocation occurs.
Simple
eh???

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Mirek Fidler
Guest





PostPosted: Fri Oct 21, 2005 4:18 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote

Quote:
...... Requirement for elements to be copy-constructible and
assignable limits the real usage of STL containers to storing
fundamental types plus perhaps smart pointers (with reduced performance
for later).


I routinely store complex constructs which are themselves composed of
containers of containers of elements without incident.

So do I. Are you able to do so without added complexity (like smart
pointers or similar stuff) as I am?

Mirek

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Le Chaud Lapin
Guest





PostPosted: Fri Oct 21, 2005 10:11 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote

Mirek Fidler wrote:
Quote:
I routinely store complex constructs which are themselves composed of
containers of containers of elements without incident.

So do I. Are you able to do so without added complexity (like smart
pointers or similar stuff) as I am?


Yes. I guess the point I was making is that it is OK to go beyond
storing simple data types and pointers in containers. There is a lot
of power in storing full-blown concrete classes, so an engineer should
be predisposed to creating classes that lend themselves to behave this
way, given that if it turns out to be impossible to make a class
concrete, the engineer will discover that anyway.

What I have seen is that only in recent years have programmers starting
doing things like..

map
Instead, there is a heavy reliance on pointers, with concomitant
limitations.

Introducing pointers (or references) in the system sometimes adds
unnecessary complexity. In the OP's case, simply using a handle
duplication function (DuplicateHandle in Windows) eliminates the need
for anything fancy.

However, that's not to say that fancy things are not good in other
situations.

-Le Chaud Lapin-


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Mirek Fidler
Guest





PostPosted: Fri Oct 21, 2005 10:11 pm    Post subject: Re: RAII and STL (perhaps a FAQ?) Reply with quote

Quote:
Am I doing something wrong here?

No. STL does. Requirement for elements to be copy-constructible and
assignable limits the real usage of STL containers to storing
fundamental types plus perhaps smart pointers (with reduced performance
for later).


class RAII
{
private:
// All ctors are private as is assignment
RAII(){ /* allocate resources */}
RAII(const RAII &);
RAII const & operator = (const RAII &);
struct deleter
{
void operator () (RAII *p)
{
/*deallocate resources of *p here */
}
};
public:
static boost::shared_ptr<RAII> create()
{
return boost::shared_ptr<RAII>(new RAII(),deleter());
}
};

NB only shared_ptr<RAII>'s can be created this way,RAII's can;t
be copied either.
store boost::shared_ptr<RAII>'s in your container. As soon as the
last reference to an RAII is destroyed, the deallocation occurs.
Simple
eh???

Not at all. Why something as trivial as storing non-copyable element
into map has to be so complicated?

Personally, I prefer using more capable containers that those provided
by STL:

ArrayMap<String, RAII> map; // case solved

and keeping you "smart" solutions miles away... :)

Mirek

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.