passing ref to ptr again as ref to ptr....

O

osama178

Let's say I have this code

--------------------
class GenericQueue
{
public:
bool Pop(void*& refToPtr); //--------------(1)

};

class SpecialQueue: private GenericQueue
{
public:
bool Pop(T*& refToPtr)
{
return
GenericQueue::pop(refToPtr); //--------------------(2)
}

};

Why does the statement in (2) generate an error?
 
B

Bo Persson

Let's say I have this code

--------------------
class GenericQueue
{
public:
bool Pop(void*& refToPtr); //--------------(1)

};

class SpecialQueue: private GenericQueue
{
public:
bool Pop(T*& refToPtr)
{
return
GenericQueue::pop(refToPtr); //--------------------(2)
}

};

Why does the statement in (2) generate an error?

You just cannot convert a reference to one type into a refererence to
another type, unless the latter is a base class of the first.

There is no guarantee that all T* must be the same size as a void*.


Bo Persson
 
O

osama178

You just cannot convert a reference to one type into a refererence to
another type, unless the latter is a base class of the first.

There is no guarantee that all T* must be the same size as a void*.

Bo Persson


Does that mean references and templates are not to be mixed?
And
is that why STL containers do not store references to objects?
 
B

Bo Persson

Does that mean references and templates are not to be mixed?

No, they work very well together. I think the void* is the problem
here, and that you are trying too hard to optimize the code.

I would trust my compiler here, and just write

template<class T>
class GenericQueue
{
bool Pop(T&);

};

if that is the interface needed (it probably is not - take a look at
std::queue and std::stack).

The compiler knows which types (pointers or not) are of the same size,
and can compile that to identical code.

And
is that why STL containers do not store references to objects?

Many containers will have to copy some of their contents when
inserting or erasing members. References cannot be copied.


Bo Persson
 
J

James Kanze

(e-mail address removed) wrote:

[...]
No, they work very well together. I think the void* is the
problem here, and that you are trying too hard to optimize the
code.
I would trust my compiler here, and just write
template<class T>
class GenericQueue
{
bool Pop(T&);
};

Given that he requires pointer semantics, and copying a pointer
cannot throw, there's no reason not to just use
T* pop() ;
in the generic interface.
if that is the interface needed (it probably is not - take a
look at std::queue and std::stack).

There's a slight difference. The standard containers are
designed to store values, not (only) pointers. So the
alternatives are:

-- return a T, but not be thread safe,

-- take a reference as a parameter, requiring the client to
define (and construct) and instance before hand, or

-- separate accessing the object and removing it, putting them
in two separate functions.

Globally, I think the first alternative was dismissed because of
the lack of thread safety (although I think it was what was used
in the original STL); of the latter two, the last seems to offer
the most flexibility, and was chosen.

If you limit elements in the container to types which cannot
throw when being copied, then the first is the obvious solution.
The compiler knows which types (pointers or not) are of the
same size, and can compile that to identical code.

Almost none do.
And that's not the only point---you don't want to load your
header files with complicated implementations, increasing
coupling and compile times. In the absense of export, you may
want to factorize the implementation into a non-generic part
simply to reduce coupling.
Many containers will have to copy some of their contents when
inserting or erasing members. References cannot be copied.

More to the point, the STL uses value semantics by default (as
does the rest of C++). If the STL stored a reference, would
that mean that the client code would have to ensure the
lifetime of the object? I don't think storing references is a
good idea, myself.
 
G

gpderetta

(e-mail address removed) wrote:
[...]
Does that mean references and templates are not to be mixed?
No, they work very well together. I think the void* is the
problem here, and that you are trying too hard to optimize the
code.
I would trust my compiler here, and just write
template<class T>
class GenericQueue
{
bool Pop(T&);
};

Given that he requires pointer semantics, and copying a pointer
cannot throw, there's no reason not to just use
T* pop() ;
in the generic interface.
if that is the interface needed (it probably is not - take a
look at std::queue and std::stack).

There's a slight difference. The standard containers are
designed to store values, not (only) pointers. So the
alternatives are:

-- return a T, but not be thread safe,

[...]
Globally, I think the first alternative was dismissed because of
the lack of thread safety (although I think it was what was used
in the original STL); of the latter two, the last seems to offer
the most flexibility, and was chosen.

IIRC, it had more to do with exception safety: if the copy constructor
throws an exception when returning the pop'd object, you will lose
the
object with no way to recover it (it has already been removed from
the
internal queue). There is no such a problem with the
separated 'T&top()' and 'void pop()'

HTH,
 
J

James Kanze

(e-mail address removed) wrote:
[...]
Does that mean references and templates are not to be mixed?
No, they work very well together. I think the void* is the
problem here, and that you are trying too hard to optimize the
code.
I would trust my compiler here, and just write
template<class T>
class GenericQueue
{
bool Pop(T&);
};
Given that he requires pointer semantics, and copying a pointer
cannot throw, there's no reason not to just use
T* pop() ;
in the generic interface.
if that is the interface needed (it probably is not - take a
look at std::queue and std::stack).
There's a slight difference. The standard containers are
designed to store values, not (only) pointers. So the
alternatives are:
-- return a T, but not be thread safe,
[...]
Globally, I think the first alternative was dismissed because of
the lack of thread safety (although I think it was what was used
in the original STL); of the latter two, the last seems to offer
the most flexibility, and was chosen.
IIRC, it had more to do with exception safety: if the copy
constructor throws an exception when returning the pop'd
object, you will lose the object with no way to recover it (it
has already been removed from the internal queue). There is
no such a problem with the separated 'T&top()' and 'void
pop()'

Yes. I don't know why I wrote thread---the issue was definitely
exceptions, and the impossibility to offer a strong guarantee.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top