473,480 Members | 1,980 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Convention for Object Lifetime Requirement

Suppose that a class A depends on class B because an object of class B
is passed into A's constructor. See below:

class B { ... };

class A {
public:
A(B const& b);
...
};

Does anybody use any convention (comment, code, etc) to indicate
whether or not the object of class A requires b to exist beyond the
call to A's constructor?

For example, in the case of copy constructors, I would find odd to
learn that for objects o1 and o2 of certain class O, where o1 was
constructed from o2, o1 requires o2 to exist beyond the call to o1's
constructor.

I would like to extend the discussion to other types of dependencies,
for example, when A declares a member function that takes an object of
class B as a parameter.

Thanks:

Belebele

Mar 29 '06 #1
12 1985
On 29 Mar 2006 11:23:30 -0800, "Belebele" <be******@gmail.com> wrote:
Suppose that a class A depends on class B because an object of class B
is passed into A's constructor. See below:

class B { ... };

class A {
public:
A(B const& b);
...
};

Does anybody use any convention (comment, code, etc) to indicate
whether or not the object of class A requires b to exist beyond the
call to A's constructor?
No. This setting seems to be an anti-idiom. When A depends on B then
let A create B in the constructor:

class A {
B b;
public:
A (int i) : b(i) {}
...
};
For example, in the case of copy constructors, I would find odd to
learn that for objects o1 and o2 of certain class O, where o1 was
constructed from o2, o1 requires o2 to exist beyond the call to o1's
constructor.
In that case you can only prevent copy construction and assignment.
I would like to extend the discussion to other types of dependencies,
for example, when A declares a member function that takes an object of
class B as a parameter.


References to 'outside' objects also violates encapsulation. If A
really needs B then pass a B object as argument to the function, eg.

class A {
// as above
void foo (const B& b, float f) { ... }
...
};

Best wishes,
Roland Pibinger

Mar 29 '06 #2
Belebele wrote:
Suppose that a class A depends on class B because an object of class B
is passed into A's constructor. See below:

class B { ... };

class A {
public:
A(B const& b);
...
};

Does anybody use any convention (comment, code, etc) to indicate
whether or not the object of class A requires b to exist beyond the
call to A's constructor?
Yes, use smart pointers instead of raw pointers or references when
there is some special relationship. For instance, if A takes over
ownership of a B object, pass a std::auto_ptr<B> into A's constructor,
or if A doesn't uniquely own that B object but needs it to exist after
the constructor has completed, accept a std::tr1::shared_ptr<B> (or
boost::shared_ptr<B>) or similar and store it as a member of A.
For example, in the case of copy constructors, I would find odd to
learn that for objects o1 and o2 of certain class O, where o1 was
constructed from o2, o1 requires o2 to exist beyond the call to o1's
constructor.

I would like to extend the discussion to other types of dependencies,
for example, when A declares a member function that takes an object of
class B as a parameter.


The same idioms apply in these two cases, methinks.

Cheers! --M

Mar 29 '06 #3
Roland Pibinger wrote:
No. This setting seems to be an anti-idiom. When A depends on B then
let A create B in the constructor:

class A {
B b;
public:
A (int i) : b(i) {}
...
};


Google for "construction encapsulation".

(And it's heartwarming to see how, each year, this newsgroup gets posts
detracting from the good memes of yesteryear as if they were "myths", or
"anti-idioms"...)

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Mar 29 '06 #4

mlimber wrote:
Belebele wrote:
Suppose that a class A depends on class B because an object of class B
is passed into A's constructor. See below:

class B { ... };

class A {
public:
A(B const& b);
...
};

Does anybody use any convention (comment, code, etc) to indicate
whether or not the object of class A requires b to exist beyond the
call to A's constructor?


Yes, use smart pointers instead of raw pointers or references when
there is some special relationship. For instance, if A takes over
ownership of a B object, pass a std::auto_ptr<B> into A's constructor,
or if A doesn't uniquely own that B object but needs it to exist after
the constructor has completed, accept a std::tr1::shared_ptr<B> (or
boost::shared_ptr<B>) or similar and store it as a member of A.
For example, in the case of copy constructors, I would find odd to
learn that for objects o1 and o2 of certain class O, where o1 was
constructed from o2, o1 requires o2 to exist beyond the call to o1's
constructor.

I would like to extend the discussion to other types of dependencies,
for example, when A declares a member function that takes an object of
class B as a parameter.


The same idioms apply in these two cases, methinks.


If you use a reference counting smart pointer, be careful not to add
cycles to your code, because the cyclic dependency prevents refcounts
from ever going to
zero, and therefore leaves memory leaks in your code.

Also see alternative to boost::shared_ptr
http://axter.com/smartptr

----------------------------------------------------------------------------------------
David Maisonave
http://axter.com

Top ten member of C++ Expert Exchange:
http://www.experts-exchange.com/Cplusplus
----------------------------------------------------------------------------------------

Mar 29 '06 #5
In article <11********************@i39g2000cwa.googlegroups.c om>,
"Belebele" <be******@gmail.com> wrote:
Suppose that a class A depends on class B because an object of class B
is passed into A's constructor. See below:

class B { ... };

class A {
public:
A(B const& b);
...
};

Does anybody use any convention (comment, code, etc) to indicate
whether or not the object of class A requires b to exist beyond the
call to A's constructor?
A couple people have said "use a smart pointer" one even specified
shared_ptr. I think this is a bad idea in general. For one thing, there
is no guarantee that the B object passed in was created on the heap, it
might be stack based for all A knows. For another, if B is sending
itself to A, (and is also wrapped in a shared_ptr by some other means,
it can't possibly be good for it to send 'this' to A's constructor.

For example, in the case of copy constructors, I would find odd to
learn that for objects o1 and o2 of certain class O, where o1 was
constructed from o2, o1 requires o2 to exist beyond the call to o1's
constructor.

I would like to extend the discussion to other types of dependencies,
for example, when A declares a member function that takes an object of
class B as a parameter.


The general rule I use is that if the parameter is passed by reference
then the parameter is not going to be stored. The caller is free to
destroy the parameter object at anytime after the function returns. If
the parameter is passed in by pointer then it may be stored, check the
documentation to see how long (either until the end of the function,
until certain non-const member-functions are called, or until object
destruction.)

--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Mar 30 '06 #6
Daniel T. wrote:
In article <11********************@i39g2000cwa.googlegroups.c om>,
"Belebele" <be******@gmail.com> wrote:
Suppose that a class A depends on class B because an object of class B
is passed into A's constructor. See below:

class B { ... };

class A {
public:
A(B const& b);
...
};

Does anybody use any convention (comment, code, etc) to indicate
whether or not the object of class A requires b to exist beyond the
call to A's constructor?
A couple people have said "use a smart pointer" one even specified
shared_ptr. I think this is a bad idea in general. For one thing, there
is no guarantee that the B object passed in was created on the heap, it
might be stack based for all A knows.


You are right that you couldn't pass an automatic object -- that's part
of the trade-off for using this idiom. The implicit requirement of
using a smart pointer as a constructor parameter is that the B object
be created in such as way as to be compatible with using that smart
pointer, and since the deleter of some (e.g., boost::shared_ptr) can be
specified, the object could be created by various methods. Also, in the
case that B is non-copyable but A needs to retain an instance of it, a
(smart) pointer of some kind is the only option.
For another, if B is sending
itself to A, (and is also wrapped in a shared_ptr by some other means,
it can't possibly be good for it to send 'this' to A's constructor.


This is true, but there are ways around it, not least of which is
considering different designs. What we're concerned with here is making
sure that an A's stored reference to a B object doesn't dangle or leak.
Passing a raw pointer/reference gives the most flexibility but
consequently (1) communicates the least about A's intentions toward
that B object and (2) allows a greater number of errors. Using the
smart pointer idiom clarifies A's intentions by encoding and enforcing
the life time expectations for the B object by making explicit who is
responsibile for destroying B and when it should be done.
For example, in the case of copy constructors, I would find odd to
learn that for objects o1 and o2 of certain class O, where o1 was
constructed from o2, o1 requires o2 to exist beyond the call to o1's
constructor.

I would like to extend the discussion to other types of dependencies,
for example, when A declares a member function that takes an object of
class B as a parameter.


The general rule I use is that if the parameter is passed by reference
then the parameter is not going to be stored. The caller is free to
destroy the parameter object at anytime after the function returns. If
the parameter is passed in by pointer then it may be stored, check the
documentation to see how long (either until the end of the function,
until certain non-const member-functions are called, or until object
destruction.)


This is a commendable convention, however, who is to say that the user
of your code (or the programmer who maintains it in several years) will
follow it? Using the smart pointer idiom enforces the life time
management requirements that are required by A in a way that your
convention and personal discipline cannot.

Cheers! --M

Mar 30 '06 #7
Axter wrote:
Also see alternative to boost::shared_ptr
http://axter.com/smartptr


While we're on it, you could also see Loki::SmartPtr from _Modern C++
Design_:

http://loki-lib.sourceforge.net/

Cheers! --M

Mar 30 '06 #8
In article <11*********************@e56g2000cwe.googlegroups. com>,
"mlimber" <ml*****@gmail.com> wrote:
Daniel T. wrote:
In article <11********************@i39g2000cwa.googlegroups.c om>,
"Belebele" <be******@gmail.com> wrote:
Suppose that a class A depends on class B because an object of class B
is passed into A's constructor. See below:

class B { ... };

class A {
public:
A(B const& b);
...
};

Does anybody use any convention (comment, code, etc) to indicate
whether or not the object of class A requires b to exist beyond the
call to A's constructor?


A couple people have said "use a smart pointer" one even specified
shared_ptr. I think this is a bad idea in general. For one thing, there
is no guarantee that the B object passed in was created on the heap, it
might be stack based for all A knows.


You are right that you couldn't pass an automatic object -- that's part
of the trade-off for using this idiom. The implicit requirement of
using a smart pointer as a constructor parameter is that the B object
be created in such as way as to be compatible with using that smart
pointer, and since the deleter of some (e.g., boost::shared_ptr) can be
specified, the object could be created by various methods. Also, in the
case that B is non-copyable but A needs to retain an instance of it, a
(smart) pointer of some kind is the only option.
For another, if B is sending
itself to A, (and is also wrapped in a shared_ptr by some other means,
it can't possibly be good for it to send 'this' to A's constructor.


This is true, but there are ways around it, not least of which is
considering different designs. What we're concerned with here is making
sure that an A's stored reference to a B object doesn't dangle or leak.
Passing a raw pointer/reference gives the most flexibility but
consequently (1) communicates the least about A's intentions toward
that B object and (2) allows a greater number of errors. Using the
smart pointer idiom clarifies A's intentions by encoding and enforcing
the life time expectations for the B object by making explicit who is
responsibile for destroying B and when it should be done.
For example, in the case of copy constructors, I would find odd to
learn that for objects o1 and o2 of certain class O, where o1 was
constructed from o2, o1 requires o2 to exist beyond the call to o1's
constructor.

I would like to extend the discussion to other types of dependencies,
for example, when A declares a member function that takes an object of
class B as a parameter.


The general rule I use is that if the parameter is passed by reference
then the parameter is not going to be stored. The caller is free to
destroy the parameter object at anytime after the function returns. If
the parameter is passed in by pointer then it may be stored, check the
documentation to see how long (either until the end of the function,
until certain non-const member-functions are called, or until object
destruction.)


This is a commendable convention, however, who is to say that the user
of your code (or the programmer who maintains it in several years) will
follow it? Using the smart pointer idiom enforces the life time
management requirements that are required by A in a way that your
convention and personal discipline cannot.


My convention isn't the only one that requires discipline. Use of a
smart pointer also requires discipline. When an object is placed in a
smart pointer, one must ensure that (a) the object was dynamically
allocated, (b) that the smart pointer knows how to properly deallocate
it and (c) no other pointer to that object exists either as a raw
pointer, or within another smart pointer type.

So given, for example, two libraries that I want to use which use two
different smart pointers, what benefit do they give me when I want to
share an object between them? If anything my plight is worse than if
they (or at least one of them) used raw pointers.

Please understand I think smart pointers are a great idea, they are used
to excellent effect in some languages where every object is held by one.
But unless and until one smart pointer class holds every dynamically
allocated object no matter what library creates it, and cannot be
accidentally made to hold objects that were not dynamically allocated,
use of the smart pointer requires no less discipline, nor is it any less
error prone than use of a raw pointer.

--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Mar 31 '06 #9
Daniel T. wrote:
"mlimber" <ml*****@gmail.com> wrote:
Daniel T. wrote:
The general rule I use is that if the parameter is passed by reference
then the parameter is not going to be stored. The caller is free to
destroy the parameter object at anytime after the function returns. If
the parameter is passed in by pointer then it may be stored, check the
documentation to see how long (either until the end of the function,
until certain non-const member-functions are called, or until object
destruction.)
This is a commendable convention, however, who is to say that the user
of your code (or the programmer who maintains it in several years) will
follow it? Using the smart pointer idiom enforces the life time
management requirements that are required by A in a way that your
convention and personal discipline cannot.


My convention isn't the only one that requires discipline. Use of a
smart pointer also requires discipline. When an object is placed in a
smart pointer, one must ensure that (a) the object was dynamically
allocated, (b) that the smart pointer knows how to properly deallocate
it and (c) no other pointer to that object exists either as a raw
pointer, or within another smart pointer type.


Of course you are right that different discipline is also required for
proper smart pointer usage. My point (perhaps poorly communicated) was
primarily that *if* the smart pointer is used properly (just as it is
expected that one will not pass a dangling reference/pointer into
A::A() in your convention), then passing one to or returning one from a
function clearly communicates and enforces expectations for the
life-time management of that object. Use of smart pointers are
certainly not fool-proof, but using them across the board generally
makes things simpler and safer (especially when exceptions come into
play).

Compared to this explicitness, using raw pointers/references
necessitates nothing about life-time management since one can use them
"properly" in a number of ways -- your excellent convention being just
one of those. Smart pointers have (relatively) clearly defined rules
and expectations; raw pointers do not. Your convention may exist in
your personal or your company's coding standards, the written
documentation, or code comments, but that makes it more dependent on
the people involved and their discipline. Making life-time management
instead depend on the language rules via RAII and smart pointers makes
code more robust.
So given, for example, two libraries that I want to use which use two
different smart pointers, what benefit do they give me when I want to
share an object between them? If anything my plight is worse than if
they (or at least one of them) used raw pointers.
Well, if one uses std::auto_ptr and the other uses
std::tr1::shared_ptr, obviously they are incompatible because of
differing requirements, and such a case would be incompatible in your
convention as well, though I would hasten to point out that, unlike
with smart pointers, this incompatibility would not be clear just from
the interface.

If one uses std::tr1::shared_ptr and the other a roughly equivalent
reference-counted smart pointer (e.g., Loki::SmartPtr), then you do
have a problem, though you might be able to resolve it by supplying
compatible policies (for Loki::SmartPtr) or with a partial
specialization of the smart pointer class (for some other
implementation). ISTM that that problem will be mitigated somewhat
if/when shared_ptr becomes an official part of the standard. Then you
could justly complain to the library vendor that they should use
standard features rather than non-standard but equivalent ones.

In my experience, most third-party libraries today don't offer smart
pointers in their interfaces mainly because of the non-standard nature
of the beasts. Hopefully, that will change for the better if/when the
standardization includes more smart pointers, but for the time being,
one can use smart pointers internally in the project and convert them
to raw pointers when sending to third-party libraries (cf. using
std::vector with C APIs).
Please understand I think smart pointers are a great idea, they are used
to excellent effect in some languages where every object is held by one.
But unless and until one smart pointer class holds every dynamically
allocated object no matter what library creates it, and cannot be
accidentally made to hold objects that were not dynamically allocated,
use of the smart pointer requires no less discipline, nor is it any less
error prone than use of a raw pointer.


I agree fully that the discipline required for using smart pointers is
different, but I would argue that their use is indeed less error prone,
especially in the face of exceptions. The same thing is true of using
std::vector instead of C-style arrays: though the former requires
different discipline for proper usage (e.g., making sure iterators are
not invalidated), its benefits -- clearly defined life-time management,
exception-safety, and elimination of common programmer errors (e.g.,
delete instead of delete[]) -- out-weigh the downsides in most
circumstances (cf. FAQ 34.1).

Cheers! --M

Mar 31 '06 #10
mlimber wrote:
You are right that you couldn't pass an automatic object -- that's part
of the trade-off for using this idiom. The implicit requirement of
using a smart pointer as a constructor parameter is that the B object
be created in such as way as to be compatible with using that smart
pointer, and since the deleter of some (e.g., boost::shared_ptr) can be
specified, the object could be created by various methods.
I did not know such feature (the deleter policy for the smart pointer)
existed in some standard way (that is, on a library somewhere). It
occurs to me that it can be put to good use in case the B object is not
in a smart pointer form. If the client of A knows that the B object is
guaranteed to meet the lifetime requirements imposed by A, it can
create a smart pointer to B with a deleter that does nothing and pass
it to A.
This is a commendable convention, however, who is to say that the user
of your code (or the programmer who maintains it in several years) will
follow it?
Enough said. However, if we do not know better (or are not fully
comfortable with the alternatives), the comment convention is, well,
highly commendable. (I will stick to using references as parameters if
clients are required to provide the B object, and pointers if the B
object may or may not be provided)
Cheers! --M


Apr 1 '06 #11
On Wed, 29 Mar 2006 19:46:30 GMT, rp*****@yahoo.com (Roland Pibinger)
wrote:
On 29 Mar 2006 11:23:30 -0800, "Belebele" <be******@gmail.com> wrote:
Suppose that a class A depends on class B because an object of class B
is passed into A's constructor. See below:

class B { ... };

class A {
public:
A(B const& b);
...
};

Does anybody use any convention (comment, code, etc) to indicate
whether or not the object of class A requires b to exist beyond the
call to A's constructor?


No. This setting seems to be an anti-idiom. When A depends on B then
let A create B in the constructor:


Actually, there is an idiom where the above code makes sense:
dependency inversion, e.g.

Connection conn (....);
Database db (conn);
Table mytable (db);
MyObject* pObj = mytable.readByPrimaryKey (123);

To prevent errors (or make them less probable) all objects in the
'dependeny inversion chain' should be non-copyable/non-assignable.

Best wishes,
Roland Pibinger
Apr 9 '06 #12
mlimber wrote:
Daniel T. wrote:
A couple people have said "use a smart pointer" one even specified
shared_ptr. I think this is a bad idea in general. For one thing, there
is no guarantee that the B object passed in was created on the heap, it
might be stack based for all A knows.


You are right that you couldn't pass an automatic object -- that's part
of the trade-off for using this idiom. The implicit requirement of
using a smart pointer as a constructor parameter is that the B object
be created in such as way as to be compatible with using that smart
pointer, and since the deleter of some (e.g., boost::shared_ptr) can be
specified, the object could be created by various methods. Also, in the
case that B is non-copyable but A needs to retain an instance of it, a
(smart) pointer of some kind is the only option.
For another, if B is sending
itself to A, (and is also wrapped in a shared_ptr by some other means,
it can't possibly be good for it to send 'this' to A's constructor.


This is true, but there are ways around it, not least of which is
considering different designs. What we're concerned with here is making
sure that an A's stored reference to a B object doesn't dangle or leak.
Passing a raw pointer/reference gives the most flexibility but
consequently (1) communicates the least about A's intentions toward
that B object and (2) allows a greater number of errors. Using the
smart pointer idiom clarifies A's intentions by encoding and enforcing
the life time expectations for the B object by making explicit who is
responsibile for destroying B and when it should be done.


I retract both of these concessions to Daniel T.

First, using a custom deleter (in particular, a deleter that does
nothing), one certainly can send an object allocated on the stack to a
function expecting a smart pointer such as std::tr1::shared_ptr. (One
might worry that the function might try to retain a copy of the pointer
to the object, which will dangle when the automatic object goes out of
scope. This is true, but it equally applies to raw pointers.)

Second, std::tr1::shared_ptr certainly can point to "this" by
inheriting from std::tr1::enable_shared_from_this. (Alternately, one
can use a boost::intrusive_ptr, though this is not part of TR1 and is
not preferred except for legacy code.)

For more details, see the online docs or chapter 1 of Bjorn Karlsson's
_Beyond the C++ Standard Library: An Introduction to Boost_.

Cheers! --M

Apr 21 '06 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
1276
by: johny smith | last post by:
Suppose there is a policy that all objects are statically declared. For example: static Car car(); Then, is there a reason to have a destructor defined for the class Car. It would seem...
8
2924
by: pt | last post by:
Hallo, i wonder how it is going to be of this code below regarding of the return of temporary object. Prototypes: =========== bool Activation(TCHAR *c); std::basic_string<TCHAR> GetFile();
14
3123
by: MuZZy | last post by:
Hi, Lately i've been (and still am) fixing some memory leaks problems in the project i just took over when i got this new job. Among the other issues i've noticed that for localy created objects...
2
1463
by: Tarren | last post by:
Hi: What would be some standard convention to follow when writing web services for return types for .NET only data types? I initially wrote my web service that returns some XML as...
4
1714
by: REH | last post by:
I've been trying to better understand the subtle rules for object lifetime. The standard says that pointers to the memory of a dynamically allocated object may be used in limited ways after the...
20
13284
by: Justin Rich | last post by:
so im trying to be good and not leave anything hanging open but i guess ive seen a variety of ways to kill objects.. is there like a recommended way? basically im looking for best practices for...
3
2314
by: nagashre | last post by:
class A { public: A():a(0), b(0){} handleMyMsg( char* aa, char*bb); private: processMessage();
6
2651
by: better_cs_now | last post by:
Hello all, class Foo {/* Details don't matter */}; class Bar { public: Bar(): m_Foo(/* Construct a Foo however it wants to be constructed */); const Foo &GetFoo() const { return m_Foo; }...
6
1522
by: Rajesh | last post by:
I read Global Object's constructor will be called before main() function; In which situation it can be really helpful? Is it good practice use Global object and its constructor ? Thanks,...
0
7054
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
7057
Oralloy
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,...
0
7102
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
5357
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
4495
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3008
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
3000
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1310
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
0
199
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.