473,507 Members | 5,060 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

API design choice pointer vs. object

Hi,
I am designing an API and the problem that I have is more of a
design issue. In my API say I have a class A and B, as shown below

class A{
public:
void doSomethingWithB( B * b)
{
//do something with b
//possibly store in a list
listB.push_back(b);
}
private:
std::vector<B *> listB;
};

class B
{
///some declarations and /or data members
};

Now the problem is either the interface to doSomethingWithB could be

void doSomethingWithB( B * b)
or
void doSomethingWithB( B & b)

If I use pointers they come with all the mess as then I might have to
do some sort of reference counting on them to tell somebody that I am
storing the pointer to B and possibly call delete or unref on them when
I remove them from the list if the ref count goes to 0. This adds lots
of memory management overhead /code to the piece above.

If I use reference rather then pointers, then probably I am not giving
the user of the API the full flexibility. I am not very sure that what
pros /cons will it have if I don't provide a interface with pointers.

Frankly until now I almost used to use pointers everywhere for member
objects, for method parameters, method return type. And this I feel is
bad.

If people can provide reasons for/against the pointer/reference
interface then it would help a lot.

Thanks,
Divick

Mar 14 '06 #1
17 2571
Divick wrote:
[..]
If people can provide reasons for/against the pointer/reference
interface then it would help a lot.


Can you say, "Google"? "Pointer versus reference" discussion is such
a dead horse that I can barely see the tracks in the dust where the whip
hit it last time we were beating it.

V
--
Please remove capital As from my address when replying by mail
Mar 14 '06 #2

Divick wrote:
Hi,
I am designing an API and the problem that I have is more of a
design issue. In my API say I have a class A and B, as shown below

class A{
public:
void doSomethingWithB( B * b)
{
//do something with b
//possibly store in a list
listB.push_back(b);
}
private:
std::vector<B *> listB;
};

class B
{
///some declarations and /or data members
};

Now the problem is either the interface to doSomethingWithB could be

void doSomethingWithB( B * b)
or
void doSomethingWithB( B & b)


Is B polymorphic? If yes you have your answer, it must be the former.

Do you want to keep copies of B or the actual B itself? If copies then
it can be the later but otherwise must be former.

For reference counting and such if you have the option you should use
Boost's shared_ptr. If not then create one...it isn't too tough.

Mar 14 '06 #3
Noah Roberts <ro**********@gmail.com> wrote:

Divick wrote:
Now the problem is either the interface to doSomethingWithB could be

void doSomethingWithB( B * b)
or
void doSomethingWithB( B & b)


Is B polymorphic? If yes you have your answer, it must be the former.


I think polymorphism works with references too:
#include <iostream>

class A {
public:
virtual ~A() { }
virtual void do_something() { std::cout << "A::do_something()\n"; }
};

class B : public A {
public:
virtual void do_something() { std::cout << "B::do_something()\n"; }
};

void do_it(A& a)
{
a.do_something();
}

int main()
{
B b;
do_it(b);

return 0;
}
Output:
B::do_something()
--
Marcus Kwok
Mar 14 '06 #4
Noah Roberts wrote:
Divick wrote:
Hi,
I am designing an API and the problem that I have is more of a
design issue. In my API say I have a class A and B, as shown below

class A{
public:
void doSomethingWithB( B * b)
{
//do something with b
//possibly store in a list
listB.push_back(b);
}
private:
std::vector<B *> listB;
};

class B
{
///some declarations and /or data members
};

Now the problem is either the interface to doSomethingWithB could be

void doSomethingWithB( B * b)
or
void doSomethingWithB( B & b)


Is B polymorphic? If yes you have your answer, it must be the former.


That should not be a factor in making a determiniation.
If B is polymorphic, it will work with pointers or reference type.
Author's like Herb Sutter, recommend preferring to use reference type
over pointer type, because a pointer can mean two things, and therefore
more ambiguous.

I recommend a reference type, unless you know for sure you need a
pointer.

Mar 14 '06 #5
void doSomethingWithB( B * b)
or
void doSomethingWithB( B & b)

If I use pointers they come with all the mess as then I might have to
do some sort of reference counting on them to tell somebody that I am
storing the pointer to B and possibly call delete or unref on them when
I remove them from the list if the ref count goes to 0. This adds lots
of memory management overhead /code to the piece above.

If I use reference rather then pointers, then probably I am not giving
the user of the API the full flexibility. I am not very sure that what
pros /cons will it have if I don't provide a interface with pointers.


....or quite opposite. In fact, when designed right, you can gain much
more flexibility without pointers and passing ownership (actually, this
is about ownership rahter than anything else). See

http://upp.sourceforge.net/www$uppweb$overview$en-us.html

(I think the "Who owns widgets" section is the most relevant here).

Mirek
Mar 15 '06 #6
In article <11**********************@i39g2000cwa.googlegroups .com>,
"Divick" <di************@gmail.com> wrote:
Hi,
I am designing an API and the problem that I have is more of a
design issue. In my API say I have a class A and B, as shown below

class A{
public:
void doSomethingWithB( B * b)
{
//do something with b
//possibly store in a list
listB.push_back(b);
}
private:
std::vector<B *> listB;
};

class B
{
///some declarations and /or data members
};

Now the problem is either the interface to doSomethingWithB could be

void doSomethingWithB( B * b)
or
void doSomethingWithB( B & b)

If people can provide reasons for/against the pointer/reference
interface then it would help a lot.


In this particular case, because of the possibility of A storing the
object beyond the return of the function, I would use a 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 15 '06 #7
>>..or quite opposite. In fact, when designed right, you can gain much
more flexibility without pointers and passing ownership (actually, this
is about ownership rahter than anything else). See http://upp.sourceforge.net/www$uppweb$overview$en-us.html (I think the "Who owns widgets" section is the most relevant here).

I did not really get the point that this page is referring to. Could
you please explain what this page tries to explain.

Thanks,
Divick

Mar 16 '06 #8
>>In this particular case, because of the possibility of A storing the
object beyond the return of the function, I would use a pointer.

What is the reason behind? Could you please elaborate this more.

Thanks,
Divick

Mar 16 '06 #9
Divick wrote:
(I think the "Who owns widgets" section is the most relevant
here).


I did not really get the point that this page is referring to. Could
you please explain what this page tries to explain.


It's probably referring to some lifetime management issues.

You should have a clear policy of how objects are allocated and how
objects are deleted.

If you are pushing "random" pointers into a list, who manages the
lifetime of the object to which it points? Is it the list? So that all
accesses are done via the list, and if it is removed from the list it is
destroyed? Is it some other entity? Will that other enitity remove it
from the list?

You can use a smart pointer to do the reference counting for you, in
which case I suggest boost::shared_ptr.

Ben Pope
--
I'm not just a number. To many, I'm known as a string...
Mar 16 '06 #10

Marcus Kwok wrote:
Noah Roberts <ro**********@gmail.com> wrote:

Divick wrote:
Now the problem is either the interface to doSomethingWithB could be

void doSomethingWithB( B * b)
or
void doSomethingWithB( B & b)


Is B polymorphic? If yes you have your answer, it must be the former.


I think polymorphism works with references too:
#include <iostream>

class A {
public:
virtual ~A() { }
virtual void do_something() { std::cout << "A::do_something()\n"; }
};

class B : public A {
public:
virtual void do_something() { std::cout << "B::do_something()\n"; }
};

void do_it(A& a)
{
a.do_something();
}

int main()
{
B b;
do_it(b);

return 0;
}
Output:
B::do_something()


That's nice, now go look at the OP's question again. Both replies to
my answer missed an important detail about the OP's code.

Mar 16 '06 #11
Ben Pope wrote:
Divick wrote:
(I think the "Who owns widgets" section is the most relevant
here).

I did not really get the point that this page is referring to. Could
you please explain what this page tries to explain.

It's probably referring to some lifetime management issues.


Bingo! ;)
You can use a smart pointer to do the reference counting for you, in
which case I suggest boost::shared_ptr.


Or you can design your code so that it does majority of lifetime
managemenent by scope destructors.

Mirek
Mar 16 '06 #12
>> > Divick wrote:
>> Now the problem is either the interface to doSomethingWithB could be
>>
>> void doSomethingWithB( B * b)
>> or
>> void doSomethingWithB( B & b)
Noah Roberts <ro**********@gmail.com> wrote:
> Is B polymorphic? If yes you have your answer, it must be the former.
Marcus Kwok wrote:
I think polymorphism works with references too:

Noah Roberts <ro**********@gmail.com> wrote: That's nice, now go look at the OP's question again. Both replies to
my answer missed an important detail about the OP's code.


OK, I re-read the OP's question, and I'm sorry but I still don't see
what this "important detail" is.
#include <iostream>
#include <vector>

class B {
public:
virtual ~B() { }
virtual void blah() { std::cout << "B::blah()\n"; }
};

class C : public B {
public:
virtual void blah() { std::cout << "C::blah()\n"; }
};

class A {
public:
void doSomethingWithB(B* b)
{
listB.push_back(b);
b->blah();
}

void doSomethingWithB(B& b)
{
listB.push_back(&b);
b.blah();
}

private:
std::vector<B *> listB;
};
int main()
{
A a;
B b;
C c;
a.doSomethingWithB(&b);
a.doSomethingWithB(&c);

a.doSomethingWithB(b);
a.doSomethingWithB(c);
}
Output:
B::blah()
C::blah()
B::blah()
C::blah()

--
Marcus Kwok
Mar 16 '06 #13
Marcus Kwok <ri******@gehennom.net.invalid> wrote:
OK, I re-read the OP's question, and I'm sorry but I still don't see
what this "important detail" is.


Sorry for following up to myself, but upon thinking, maybe you meant the
part about storing them in a vector and retaining polymorphic behavior.
#include <iostream>
#include <vector>

class B {
public:
virtual ~B() { }
virtual void blah() { std::cout << "B::blah()\n"; }
};

class C : public B {
public:
virtual void blah() { std::cout << "C::blah()\n"; }
};

class A {
public:
void doSomethingWithB(B* b)
{
listB.push_back(b);
b->blah();
}

void doSomethingWithB(B& b)
{
listB.push_back(&b);
b.blah();
}

void doSomethingWithAllB()
{
std::cout << "ALL:\n";
typedef std::vector<B*>::const_iterator CI;
for (CI i = listB.begin(); i != listB.end(); ++i) {
(*i)->blah();
}
}

private:
std::vector<B*> listB;
};
int main()
{
A a;
B b;
C c;
a.doSomethingWithB(&b);
a.doSomethingWithB(&c);

std::cout << '\n';

a.doSomethingWithB(b);
a.doSomethingWithB(c);

std::cout << '\n';

a.doSomethingWithAllB();
}
Output:
B::blah()
C::blah()

B::blah()
C::blah()

ALL:
B::blah()
C::blah()
B::blah()
C::blah()

--
Marcus Kwok
Mar 16 '06 #14
In article <11**********************@v46g2000cwv.googlegroups .com>,
"Divick" <di************@gmail.com> wrote:
In this particular case, because of the possibility of A storing the
object beyond the return of the function, I would use a pointer.


What is the reason behind? Could you please elaborate this more.


1) A holds pointers to B's so it makes sense to accept pointers in the
member-function that receives the B's.

2) The primary reason references were added to the language was to
facilitate operator overloading. In those functions, the object is never
stored beyond the end of the function. I tend to follow suit.
--
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 17 '06 #15
I would suggest you avoid manually managing scope where possible. Even
a simple boost::scoped_ptr is preferable. Also, if lifetime tracking is
an issue, then take a good long look at boost::weak_ptr. The
shared_ptr/weak_ptr combo has become an integral part of my run-time
polymorphic class design, it just saves so many headaches.

But, as suggested above, first try and analyse the lifetime of B's if
possible. In library design lifetime analysis is often difficult
because you need to make some assumptions about how your library will
be used.

Good Luck!
Jeremy Jurksztowicz

Mar 17 '06 #16
>>I would suggest you avoid manually managing scope where possible. Even
a simple boost::scoped_ptr is preferable. Also, if lifetime tracking is
an issue, then take a good long look at boost::weak_ptr. The
shared_ptr/weak_ptr combo has become an integral part of my run-time
polymorphic class design, it just saves so many headaches.
I have several questions with respect to smart pointers, since you and
others as well have advised to use them.

1. Is shared_ptr and other smart pointers thread safe? I am planning to
use them in a threaded and multiprocessor environment.
2. I don't want to expose to the client programmer that the return type
of some method is a boost::smart_ptr because the client programmer
might not be conversant with the smart pointers and I do not want him
to delve into how I handle the pointes internally in my API. If I do a
typedef the types like typedef HANDLE boost::shared_ptr<MyClass> then I
will need to document that the client programmer can use that HANDLE as
he would use pointer to MyClass, but it might confuse him altogether.
So the question really is "Is it a good idea to expose to the end user
the boost types as return values?"
3. Since boost pointers require the template class passed should have
the destructor as public, but what if I need to have a class with
protected destructor?
But, as suggested above, first try and analyse the lifetime of B's if
possible. In library design lifetime analysis is often difficult
because you need to make some assumptions about how your library will
be used.


As far as managing lifetimes are concerned, I understand that passing
as reference is fine in the method parameters if the function is not
going to store the object. Since references to objects on stack
automatically get deleted due to scope, there is no problem or
ambiguity.

The problem really comes when you need to return pointers or objects
from functions and when you need to store the pointers/objects. My API
needs to return objects/pointers to the client programmer of some
objects created by my Factory classes. Since I cannot return reference
to an object created on the stack (as it will get deleted as soon as
the function returns), I will need to call new then either I can return
the pointer or I can return the reference like this:

A& createObjA()
{
A &b = *(new B()); //B subclasses from A

//Store the b somewhere because the object b is some system
resource
//which I need to keep track of.
code to store object b somewhere
return b;
}
I have rarely seen any API do this i.e. returning a reference to an
object created on heap. Is it considered a bad practice or what?

or
A* createPtrA()
{
A *a = new B();
return a;
}
Most API's use this kind of syntax.
But the problem is that now since I return a pointer then if the same
object needs to be passed to one of the functions of my API then the
programmer will hate to call a function with reference argument like
this:

//Function in my API accepting reference to A
void f(A &a)
//To call such function in my API the client programmer will write:
A * a = createPtrA(); //createPtrA is my API call
f(*a); //f is another function defined in my API

instead he would prefer a cleaner syntax like
A & a = createA(); //createA returns a reference to an object allocated
on heap
f(a); //And f accepts reference to A rather then pointer to A

But again I have never seen any API do any of the above instead they
would simply avoid references altogether and simply use pointers
everywhere i.e. in return types as well as arguments. And I find there
are lots of postings in this newsgroup itself where people say that
"the biggest mistake people make having knowledge of C, possibly
introduces some peoples need to use pointers everywhere". But I see out
there lots and lots of C++ API's just relying on pointers as the only
solution and believe me these API are very well known ones. All this
really leaves me astray and the question that I have is is it really
worth to design API with smart pointers / references rather then using
simple plain pointers?

Any suggestions / comments are welcome,
Thanks a ton for all the posts above,
Divick

Mar 17 '06 #17
In article <11*********************@u72g2000cwu.googlegroups. com>,
"Divick" <di************@gmail.com> wrote:
I would suggest you avoid manually managing scope where possible. Even
a simple boost::scoped_ptr is preferable. Also, if lifetime tracking is
an issue, then take a good long look at boost::weak_ptr. The
shared_ptr/weak_ptr combo has become an integral part of my run-time
polymorphic class design, it just saves so many headaches.
I have several questions with respect to smart pointers, since you and
others as well have advised to use them.

1. Is shared_ptr and other smart pointers thread safe? I am planning to
use them in a threaded and multiprocessor environment.
2. I don't want to expose to the client programmer that the return type
of some method is a boost::smart_ptr because the client programmer
might not be conversant with the smart pointers and I do not want him
to delve into how I handle the pointes internally in my API. If I do a
typedef the types like typedef HANDLE boost::shared_ptr<MyClass> then I
will need to document that the client programmer can use that HANDLE as
he would use pointer to MyClass, but it might confuse him altogether.
So the question really is "Is it a good idea to expose to the end user
the boost types as return values?"
3. Since boost pointers require the template class passed should have
the destructor as public, but what if I need to have a class with
protected destructor?
But, as suggested above, first try and analyse the lifetime of B's if
possible. In library design lifetime analysis is often difficult
because you need to make some assumptions about how your library will
be used.


As far as managing lifetimes are concerned, I understand that passing
as reference is fine in the method parameters if the function is not
going to store the object. Since references to objects on stack
automatically get deleted due to scope, there is no problem or
ambiguity.

The problem really comes when you need to return pointers or objects
from functions and when you need to store the pointers/objects. My API
needs to return objects/pointers to the client programmer of some
objects created by my Factory classes.


As far as managing lifetimes are concerned, anytime you have more than
one pointer/reference pointing/referring to the same object, you have to
worry about when the destructor will be called on that object and make
sure that both holders know when that will be. *EVEN* when you pass a
pointer/reference in a method parameter and you don't plan on storing it
past the end of that method. (In a multi-threaded situation, for
example, the objects delete could be called in the middle of your
method.)

One way to solve the problem is to make sure only one reference/pointer
is connected to every object. As such, I would recommend against you
passing a reference to an object to the client *and* storing it in the
server class. IE:

A& createObjA()
{
A &b = *(new B()); //B subclasses from A

//Store the b somewhere because the object b is some system resource
//which I need to keep track of.
// code to store object b somewhere
return b;
}

Is a bad idea. I will go so far as to say that the only time a function
should return a modifiable reference is if it returns '*this' (or if you
are writing a basic container class.) In all other cases, if returning
something it should return an object, const object&, or object* (either
const or non-const). In the later case, make it clear who is supposed to
delete the actual object and exactly when that will happen. The choices
are:

1) The client must delete it, and can do so any time it likes.
2) The client must *not* delete it. Instead, the server will delete it
when particular functions are called (and in its destructor.)

If the function returns a const object&, then it should be made clear
that the server class can destroy the object by the time any other
member function is called. IE returning by const object& should be
thought of only as an optimization over turning by object.

Given these rules, the below is fine:

A* createPtrA()
{
A *a = new B();
return a;
}

As long as the documentation for the function makes it clear that it is
the caller's responsibility to delete the object (choice 1 above.) Some
go so far as to wrap it in an auto_ptr, as in:

auto_ptr<A> createPtr() {
return auto_ptr<A>( new B );
}

--
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 18 '06 #18

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

Similar topics

3
1478
by: andy2O | last post by:
Hello comp.lang.py, Can you help me with ideas for the following (somewhat newbie) OO design question in Python? Note, I'm using psuedo-code, not actual Python for the examples! Background:...
2
4734
by: Jacek Dziedzic | last post by:
Hi! Say a have a class called black_box which, among other things, contains an array of cells like this: class black_box { private: // ... public: black_box_details_struct details;
0
997
by: James Saker | last post by:
I've been working on a Python class object for APRS (Automatic Position Reporting System - a digital mode used by amateur radio operators) and have been going through David Mertz's Text Processing...
1
1717
by: rt | last post by:
hi, iam using vs 2003 ,one of my .aspx all my connections,datadapter,command objects in Design view are missing????? i closed and reopen also, but there is no redline in code editor. i cant...
2
1775
by: Chris Murphy via DotNetMonster.com | last post by:
Hey guys, I've been hitting a brick wall with a problem I've come accross in developing an application. Background: The application uses one primary class that I'm trying to implement with the...
4
1569
by: =?ISO-8859-15?Q?Luigi_Malag=F2?= | last post by:
Hello, i'm new to function pointers. I have some code that parses some configuration files using flex and bison. I have to use the same parse for different files, but the information i parse have...
3
3438
by: josh | last post by:
Hi I noticed that when I make a function with a base class parameter that is a reference than at run-time the compiler calls a base class function also if I have passed a derived object. But if...
12
2158
by: bullockbefriending bard | last post by:
I am a complete ignoramus and newbie when it comes to designing and coding networked clients (or servers for that matter). I have a copy of Goerzen (Foundations of Python Network Programming) and...
0
7314
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
7372
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...
1
7030
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...
0
7482
tracyyun
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...
1
5041
isladogs
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...
0
4702
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
3179
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1540
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 ...
1
758
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.