auto_ptr

A

Andre Siqueira

Hello all,

I have a member function like thist:

Query(const std::string & id, std::auto_ptr<Modifier> modif =
std::auto_ptr<Modifier>())

when a try to instantiate a Query like

Query("123");

my compiler (aCC on HP-UX) gives me an error teling that a can pass
an objectet std::auto_ptr<Modifier> & em um objecto
std::auto_ptr<Modifier>

This is the Error:

Error 226: "AssociatedDataPersistente.cpp", line 36 # No appropriate
function found for call of 'auto_ptr::auto_ptr'. Last viable candidate
was

"std::auto_ptr<persistencia::impl::eek:bjectel::ModificadorQuery>::auto_ptr(std::auto_ptr<persistencia::impl::eek:bjectel::ModificadorQuery>
&)" ["/opt/aCC/include_std/memory", line 838]. Argument of type
'class auto_ptr<persistencia::impl::eek:bjectel::ModificadorQuery>' could
not be converted to
'std::auto_ptr<persistencia::impl::eek:bjectel::ModificadorQuery> &'.
Query q(type);
^
Warning: 1 future errors were detected and suppressed. Either
remove the '-w' option or add a '+p' option to detect and fix them
before they become fatal errors in a future release.
*** Error exit code 2


This problem started when a change the option -Aa to -AA on aCC.

Is the unique form to initialize an std::auto_ptr like that:
std::auto_ptr<Modifier> test (new Modifier);

thanks,

André Siqueira.
 
R

Rolf Magnus

Andre said:
Hello all,

I have a member function like thist:

Query(const std::string & id, std::auto_ptr<Modifier> modif =
std::auto_ptr<Modifier>())

when a try to instantiate a Query like

Query("123");

my compiler (aCC on HP-UX) gives me an error teling that a can pass
an objectet std::auto_ptr<Modifier> & em um objecto
std::auto_ptr<Modifier>

This is the Error:

Error 226: "AssociatedDataPersistente.cpp", line 36 # No appropriate
function found for call of 'auto_ptr::auto_ptr'. Last viable candidate
was

"std::auto_ptr<persistencia::impl::eek:bjectel::ModificadorQuery>::auto_ptr(std::auto_ptr<persistencia::impl::eek:bjectel::ModificadorQuery>
&)" ["/opt/aCC/include_std/memory", line 838]. Argument of type
'class auto_ptr<persistencia::impl::eek:bjectel::ModificadorQuery>' could
not be converted to
'std::auto_ptr<persistencia::impl::eek:bjectel::ModificadorQuery> &'.
Query q(type);
^
Warning: 1 future errors were detected and suppressed. Either
remove the '-w' option or add a '+p' option to detect and fix them
before they become fatal errors in a future release.
*** Error exit code 2


This problem started when a change the option -Aa to -AA on aCC.

Is the unique form to initialize an std::auto_ptr like that:
std::auto_ptr<Modifier> test (new Modifier);

Well, std::auto_ptr's copy constructor does modify the original, so its
argument is non-const. But that means you can't initialize it with a
temporary. Your default argument is a temporary.
 
P

Pete C

Well, std::auto_ptr's copy constructor does modify the original, so its
argument is non-const. But that means you can't initialize it with a
temporary. Your default argument is a temporary.

That was about to be my answer, too, and it's what I would expect for
the reasons you give. But it seems that my g++ (4.1.2) and Comeau
online both accept this code. I'm trying to understand from the
standard (8.5 para 14 perhaps?) what makes this acceptible. Any help
appreciated.
 
P

Pete C

Well, std::auto_ptr's copy constructor does modify the original, so its
argument is non-const. But that means you can't initialize it with a
temporary. Your default argument is a temporary.

OK, I get it now. The temporary auto_ptr has a cast operator to type
auto_ptr_ref. And auto_ptr has a constructor form which takes an
auto_ptr_ref object (*not* by reference). So the initialisation occurs
via in intermediate object.
Since the code is therefore OK, my guess is that the OP has done
something with command line switches to make the compiler non-
compliant.
 
K

Kai-Uwe Bux

Pete said:
That was about to be my answer, too, and it's what I would expect for
the reasons you give. But it seems that my g++ (4.1.2) and Comeau
online both accept this code. I'm trying to understand from the
standard (8.5 para 14 perhaps?) what makes this acceptible. Any help
appreciated.

Consider:

#include <memory>

typedef std::auto_ptr<int> ip;

void f ( ip x = ip( new int (0)) ) {}

void g ( ip x ) {}

int main ( void ) {
f();
g( ip( new int (0)) );
}

I think, the use of temporaries in the above is fine because the conversion
to auto_ptr_ref kicks in. The constructor for auto_ptr that is used is:

auto_ptr ( auto_ptr_ref<X> )

not

auto_ptr ( auto_ptr & )


Best

Kai-Uwe Bux
 
R

Roland Pibinger

I have a member function like thist:

Query(const std::string & id, std::auto_ptr<Modifier> modif =
std::auto_ptr<Modifier>())

BTW, you should _never_ use an auto_ptr (or any other 'smart pointer')
as argument of a function. In your example the pointed to Modifier
object probably gets deleted in the Query function.

Best regards,
Roland Pibinger
 
C

Clark S. Cox III

Roland said:
BTW, you should _never_ use an auto_ptr (or any other 'smart pointer')
as argument of a function. In your example the pointed to Modifier
object probably gets deleted in the Query function.

That advice may apply to auto_ptr, but to extend it to all smart
pointers seems a bit excessive. For instance I see nothing wrong with a
function parameter being a boost or tr1 shared_ptr (how else would one
pass such a pointer around otherwise?).
 
A

Andre Kostur

That advice may apply to auto_ptr, but to extend it to all smart
pointers seems a bit excessive. For instance I see nothing wrong with a
function parameter being a boost or tr1 shared_ptr (how else would one
pass such a pointer around otherwise?).

Even for auto_ptr, this blanket prohibition goes too far. What if your
function is intended to be a sink for the auto_ptr?
 
R

Roland Pibinger

That advice may apply to auto_ptr, but to extend it to all smart
pointers seems a bit excessive. For instance I see nothing wrong with a
function parameter being a boost or tr1 shared_ptr (how else would one
pass such a pointer around otherwise?).

The problem is that you force the client (the caller) to convert the
(real) pointer to your 'smart pointer' with all accompanying problems
for no real advantage. Your function becomes less reusable (restricted
to one 'smart pointer'). Besides that, e.g. a shared_ptr as agument
will just increase the ref-count on function entry and decrease it on
function exit.

Best regards,
Roland Pibinger
 
R

Roland Pibinger

Even for auto_ptr, this blanket prohibition goes too far. What if your
function is intended to be a sink for the auto_ptr?

I'd call that bad style when a called function deletes an object that
is passed via pointer. Maybe the rules for 'smart pointers' are
different, as 'anticipate anything'.

Best regards,
Roland Pibinger
 
A

Andre Kostur

(e-mail address removed) (Roland Pibinger) wrote in @news.utanet.at:
I'd call that bad style when a called function deletes an object that
is passed via pointer. Maybe the rules for 'smart pointers' are
different, as 'anticipate anything'.

Technically, it hasn't been passed a pointer, it has been passed an
auto_ptr by value. And, by definition of what an auto_ptr does, it would
be expected that the contents of the auto_ptr will be destroyed by the end
of the function call. If this isn't what the programmer wanted, the
function would have been written to take a reference to auto_ptr.
 
K

Kai-Uwe Bux

Roland said:
The problem is that you force the client (the caller) to convert the
(real) pointer to your 'smart pointer' with all accompanying problems
for no real advantage. Your function becomes less reusable (restricted
to one 'smart pointer'). Besides that, e.g. a shared_ptr as agument
will just increase the ref-count on function entry and decrease it on
function exit.

If all the function does is to operate on the pointee, then it should take a
reference and you call it like

f ( *ptr );

and it would not matter what kind of smart or raw pointer you pass. However,
when a function takes a smart-pointer argument, my expectation would be
that it needs the smart-pointer and not the underlying raw pointer. For
instance:

template < typename T >
class Table {

std::map< unsigned int, tr1::shared_ptr<T> > data;
unsigned int count;

insert ( tr1::shared_ptr<T> ptr ) {
data[ count ++ ] = ptr;
}

// ...

};

In this case, using the underlying pointer would create a shared_ptr with a
different reference count. That would be bad.


Best

Kai-Uwe Bux
 
R

Roland Pibinger

Technically, it hasn't been passed a pointer, it has been passed an
auto_ptr by value.

Yes, I know. 'Smart pointers' are neither smart nor pointers.
And, by definition of what an auto_ptr does, it would
be expected that the contents of the auto_ptr will be destroyed by the end
of the function call.

.... unless the function calls .release().
If this isn't what the programmer wanted, the
function would have been written to take a reference to auto_ptr.

reference to auto_ptr?? A part of the problem rather than a part of
the solution.

Best wishes,
Roland Pibinger
 
R

Rolf Magnus

Roland said:
Yes, I know. 'Smart pointers' are neither smart nor pointers.

Not sure what you want to say with that.
... unless the function calls .release().

If it does, then there is no point in letting it take an auto_ptr instead of
a regular pointer for a parameter.
reference to auto_ptr?? A part of the problem rather than a part of
the solution.

I don't see a point in using references to auto_ptr either.
 
R

Rolf Magnus

Roland said:
The problem is that you force the client (the caller) to convert the
(real) pointer to your 'smart pointer' with all accompanying problems
for no real advantage. Your function becomes less reusable (restricted
to one 'smart pointer'). Besides that, e.g. a shared_ptr as agument
will just increase the ref-count on function entry and decrease it on
function exit.

Unless it's a function that e.g. adds the smart pointer to a container.
 
G

Grizlyk

Roland said:
I'd call that bad style when a called function deletes an object that
is passed via pointer. Maybe the rules for 'smart pointers' are
different, as 'anticipate anything'.

1.
C-style pointer has no enough information about how to work with pointer,
what is why programmer must support the C-style pointer usage by own
conventions, implemented, for example, as comments, look at the following
example

//return "new[]", must be "delete[]" by external
int* get_data1();

//return "new", must be "delete" by external
int* get_data2();

//return static, do not delete outside the class
int* get_data3();

For language without garbage collecting (as C++ does) it is too raw
behaviour, it is danger by possible memory leak or double delete, because
compiler do not control the pointer usage.

2.
The auto_ptr<Tobj> is not just pointer, it is !_logical_ pair of two values:

//pointer
Tobj* ptr;
//flag "how to work with pointer"
char is_delete_by_dtor;

and some functions auto_ptr<Tobj>::??? to work with the values.

The auto_ptr<Tobj> is RAII wrapper for memory, so it is very useful as
parameter of functions.

3.
As for concrete std::auto_ptr<Tobj>, it is not clear to me why
std::auto_ptr<Tobj> must be non-const to work.

If assuming, that auto_ptr<Tobj> has method "move" to pass stored pointer
value outside the auto_ptr<Tobj> scope, the methos can and must be const.
Consider the following example:

//let's work only with object
//created by "new my_auto_ptr"
template<class Tobj>
class my_auto_ptr
{
//pointer
mutable Tobj* ptr;
/*
what mutable here?
"*" is prefix operator!
by the way, it is bad (irregular) C++ syntax
Tobj *mutable ptr; //much better and clear
*/

public:
Tobj* move()const
{
Tobj *const tmp=ptr;
ptr=0;
return tmp;
}

// danger design in return here - can store one
// pointer more than once and will get runtime
// error
Tobj* operator= (Tobj *const p)
{
if( p != ptr )
{
if(ptr)delete ptr;
ptr=p;
}
return p;
}

public:
// C-style danger here - we can pass not only new Tobj
// and will get runtime error
my_auto_ptr(Tobj *const p=0):ptr(p){}

~my_auto_ptr(){ delete ptr; }

my_auto_ptr(const my_auto_ptr& obj):ptr(obj.move()){}
my_auto_ptr& operator=(const my_auto_ptr& obj)
{
if( &obj != this)
{
if(ptr)delete ptr;
ptr=obj.move();
}
return *this;
}
};

It is work fine for exceptions of "dangers" and "const my_auto_ptr<Tobj>"
passed by value is protecting you implementation from wrong assignment to
const value.

Class "auto_ptr<Tobj>" can be example of "free-standing" class - no overhead
in comparison with POD-style data (as naked pointer).

Often the behaviour of "auto_ptr<Tobj> style" object can be used instead of
more complex in implementation "shared_ptr<Tobj> style" object.

4.
By the way, I think, that C++ must extend C-style pointer definitions, and
allow to explicit declare memory type with the halp of keywords like this

//!not C++
Tobj *heap ptr; //by new Tobj
Tobj *heap[] ptr; //by new Tobj[]
Tobj *static ptr; //writeable static memory
Tobj *code ptr; //readonly static memory
Tobj *auto ptr; //stack memory
Tobj * ptr; //indefinite memory suitable for all

Note, "Tobj *code" is not he same as "const Tobj *static" because of
different memory segment. Probably we need a "writeonly" memory pointers. We
can introduce "disable write" and "disable read" signs to pointer (abcent by
default) and write like this

Tobj *static writeonly ptr;
Tobj *static readonly ptr;
 
G

Grizlyk

some changes
2.
The auto_ptr<Tobj> is RAII wrapper for memory, so it is very useful as
parameter of functions.

So auto_ptr<Tobj> is not C-style pointer and we must do not excpect that
rules for POD pointers must be applied to auto_ptr said:
3.
As for concrete std::auto_ptr<Tobj>, it is not clear to me why
std::auto_ptr<Tobj> must be non-const to work.

If assuming, that auto_ptr<Tobj> has method "move" to pass stored pointer
value outside the auto_ptr<Tobj> scope, the methos can and must be const.

Means 'the method "move" can and must be "const" '.
//let's work only with object
//created by "new my_auto_ptr"
template<class Tobj>
class my_auto_ptr

Means created by "new Tobj"
It is work fine for exceptions of "dangers" and "const my_auto_ptr<Tobj>"
passed by value is protecting you implementation from wrong assignment to
const value.

Means "protecting your implementation"
 
A

Andre Kostur

Grizlyk said:
3.
As for concrete std::auto_ptr<Tobj>, it is not clear to me why
std::auto_ptr<Tobj> must be non-const to work.

If assuming, that auto_ptr<Tobj> has method "move" to pass stored
pointer value outside the auto_ptr<Tobj> scope, the methos can and
must be const. Consider the following example:

//let's work only with object
//created by "new my_auto_ptr"
template<class Tobj>
class my_auto_ptr
{
//pointer
mutable Tobj* ptr;
/*
what mutable here?
"*" is prefix operator!
by the way, it is bad (irregular) C++ syntax
Tobj *mutable ptr; //much better and clear
*/

public:
Tobj* move()const
{
Tobj *const tmp=ptr;
ptr=0;
return tmp;
}

// danger design in return here - can store one
// pointer more than once and will get runtime
// error
Tobj* operator= (Tobj *const p)
{
if( p != ptr )
{
if(ptr)delete ptr;
ptr=p;
}
return p;
}

public:
// C-style danger here - we can pass not only new Tobj
// and will get runtime error
my_auto_ptr(Tobj *const p=0):ptr(p){}

~my_auto_ptr(){ delete ptr; }

my_auto_ptr(const my_auto_ptr& obj):ptr(obj.move()){}
my_auto_ptr& operator=(const my_auto_ptr& obj)
{
if( &obj != this)
{
if(ptr)delete ptr;
ptr=obj.move();
}
return *this;
}
};

It is work fine for exceptions of "dangers" and "const
my_auto_ptr<Tobj>" passed by value is protecting you implementation
from wrong assignment to const value.

EVIL! By that reasoning, why don't we just make every member of every
class mutable?

The move() method semantically changes the "state" of the object, as a
result it logically must not be const. Otherwise the programmer will get
confused when he passed one of these objects by const-ref into a
function, and the object gets changed inside that function. Or phrased
differently, if I'm passing a smart pointer into a function by const-ref,
I'm not expecting it to come back out as a NULL pointer. I passed it in
as const. It's not supposed to change.
 
G

Grizlyk

Andre said:
EVIL! By that reasoning, why don't we just make every member of every
class mutable?

The move() method semantically changes the "state" of the object, as a
result it logically must not be const.

1.
Can be const, of course. The "const state" does not mean "const each member"
and appearence in C++ keyword "mutable" just proves it. Consider

my_auto_ptr<Tobj> a(new Tobj); //1
my_auto_ptr<Tobj> b(a); //2

At the point 2 we are moving "new Tobj" to "b". Is it C-style pointer
behaviour? I think not. But fortunately my_auto_ptr<Tobj> is not pointer, so
we must not duty to think, that the moving "new Tobj" from "a" violates "a"
constness.
if I'm passing a smart pointer into a function by const-ref,
I'm not expecting it to come back out as a NULL pointer.

You just must not expect from my_auto_ptr<Tobj> any return, because it is
not pointer, it is special memory wrapper with complex behaviour.

The goal of my_auto_ptr<Tobj>
1. to hold dynamic data for parameter of function
2. to delete the data on return from the function (if the data was not
used by the function) or to pass the data to user

That is why operation move() is just a kind of operation, that must be
applyed to my_auto_ptr<Tobj> only once insted to be non-const!

You can not protect yourself from double move() with the help of non-const
modifier, but as opposite, const my_auto_ptr<Tobj> can protect your
implementation from wrong assignment to my_auto_ptr<Tobj>.

Consider

void foo(const my_auto_ptr<Tobj> ptr)
{
Tobj *const a=ptr.move(); //ok
Tobj *const b=ptr.move(); //error, const do not protect
ptr=new Tobj; //error, but const will protect
}

void foo(my_auto_ptr<Tobj> ptr)
{
Tobj *const a=ptr.move(); //ok
Tobj *const b=ptr.move(); //error, non-const do not protect
ptr=new Tobj; //error, non-const do not protect
}

2.
By the way, I see now, C++ can support keyword "once", to control that the
method "move" will be called only once during lifetime of object. Very
useful, thanks to Andre Kostur.

The keyword "once" can not garantee compile time control, but at least it
can produce warnings.

void foo(const my_auto_ptr<Tobj> ptr)
{
if:):is_ok){ptr.move();}

//warning - possible double move();
//if "::is_ok" is not synced with "lib::all_ok()"
if(!lib::all_ok()){ptr.move();}
}

to avoid the warning you need write like this

void foo(const my_auto_ptr<Tobj> ptr, const int is_ok)
{
if(is_ok){ptr.move();}
else
{
if(!lib::all_ok()){ptr.move();}
}
}

Can the keyword "once" make differences for overloading?

//!not C++
//ok
Tobj *const /*once*/ move()const once;
//i think error - redeclaration of "move()const"
Tobj *const move()const;

//maybe ok together with "move()const once"
Tobj *once move()once;
//i think error - redeclaration of "move()"
Tobj * move();
 
G

Grizlyk

4.
By the way, I think, that C++ must extend C-style pointer definitions, and
allow to explicit declare memory type with the halp of keywords like this

//!not C++
Tobj *heap ptr; //by new Tobj
Tobj *heap[] ptr; //by new Tobj[]
Tobj *static ptr; //writeable static memory
Tobj *code ptr; //readonly static memory
Tobj *auto ptr; //stack memory
Tobj * ptr; //indefinite memory suitable for all


No, i think i was wrong, maybe better will switch like this:

Tobj heap *ptr; //by new Tobj
Tobj heap[] *ptr; //by new Tobj[]

- left side of "*" must describe memory of object and object, pointer point
to
- right side of "*" must describe memory of pointer and pointer itself

Tobj heap is the same as Tobj
Tobj heap* is _not_ the same as Tobj*

Tobj heap* is the same as Tobj heap *heap
Tobj heap* is _not_ the same as Tobj *heap
Tobj *static ptr; //writeable static memory

And static keyword has other meaning, maybe using "dseg"?

Tobj dseg *ptr;

Or maybe "dseg" by default, but for "indefinite memory suitable for all" use
"indefinite"?
 

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top