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

Home Posts Topics Members FAQ

auto_ptr_ref

Hello All,
My question is regarding the implementation of auto pointers - How
does the class auto_ptr_ref work?

eg: suppose I have :

auto_ptr<int> foo();

int bar()
{
auto_ptr<int*> k = foo();
}

The exact sequence of calls as I see here is (no optimizations assumed)
-
1) foo returns auto_ptr<int> by value
2) CC is called on the return value.
3) The returned auto_ptr<int> is converted to auto_ptr_ref<int> by
using operator auto_ptr_ref
4) Now since this is a copy initialization and not a direct
initialization, the RHS (whose type is now auto_ptr_ref<int>) needs to
get converted to auto_ptr<int> again - done by ctor of auto_ptr<int>
which takes auto_ptr_ref<int>
5) Now CC should be called - but again we are back to old problem - the
generated auto_ptr is temporary and hence cannot be passed as a
non-const reference to the function.

Seems I am going somewhere in cycle :-(

Josuttis' book doesnot say enough on this -

<quote>
"The mechanism relies on a slight difference between the overloading
and template argument deduction rules. This difference is too subtle to
be of use as a general programming tool, but it is sufficient to enable
the auto_ptr class to work correctly."
</quote>

Can somebody explain what I am not getting here?

Nov 23 '05 #1
14 3568
* Neelesh Bodas:

eg: suppose I have :

auto_ptr<int> foo();

int bar()
{
auto_ptr<int*> k = foo();
}

The exact sequence of calls as I see here is (no optimizations assumed)
-
1) foo returns auto_ptr<int> by value
OK.

2) CC is called on the return value.
No, there is no std::auto_ptr( std::auto_ptr const& ) copy constructor.

3) The returned auto_ptr<int> is converted to auto_ptr_ref<int> by
using operator auto_ptr_ref
OK.

4) Now since this is a copy initialization and not a direct
initialization, the RHS (whose type is now auto_ptr_ref<int>) needs to
get converted to auto_ptr<int> again - done by ctor of auto_ptr<int>
which takes auto_ptr_ref<int>
OK.

5) Now CC should be called
No, you've reached the goal.

- but again we are back to old problem - the
generated auto_ptr is temporary and hence cannot be passed as a
non-const reference to the function.


What generated auto_ptr? The one generated is the one you've named 'k'.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Nov 23 '05 #2
Hi Alf, Thanks for the help.

Actually, more I think on this, more confusion it is creating.

auto_ptr<int> foo();

int bar()
{
auto_ptr<int*> k = foo();
}

Isn't is correct that whever a function returns by value, a CC must get
called on the return value(Though it might be optimized away by the
compiler?)

No, there is no std::auto_ptr( std::auto_ptr const& ) copy constructor.


I believe that we do not need a std::auto_ptr( std::auto_ptr const& )
copy constructor - std::auto_ptr( std::auto_ptr& ) would do the work -
since the source of the copy inside "foo" is not necessarily a const :

std::auto_ptr<int> foo()
{
std::auto_ptr<int> v;
return v; // a copy ctor will be called on v since this is return by
value
}

But when I debugged throgh std::auto_ptr code I didnot find any call to
the given copy constructor (as you said in the reply.)

I am not getting where exactly I am going wrong.

Nov 23 '05 #3
* Neelesh Bodas:
Hi Alf, Thanks for the help.

Actually, more I think on this, more confusion it is creating.

auto_ptr<int> foo();

int bar()
{
auto_ptr<int*> k = foo();
}
Isn't is correct that whever a function returns by value, a CC must get
called on the return value(Though it might be optimized away by the
compiler?)
No. _Some_ constructor must be called. That call can be optimized
away, but the constructor must be available to be called (the as-if rule
for optimization).

No, there is no std::auto_ptr( std::auto_ptr const& ) copy constructor.


I believe that we do not need a std::auto_ptr( std::auto_ptr const& )
copy constructor - std::auto_ptr( std::auto_ptr& ) would do the work -
since the source of the copy inside "foo" is not necessarily a const :

std::auto_ptr<int> foo()
{
std::auto_ptr<int> v;
return v; // a copy ctor will be called on v since this is return by
value
}

But when I debugged throgh std::auto_ptr code I didnot find any call to
the given copy constructor (as you said in the reply.)


That is unfortunately a different effect.

Here the reference-to-non-const copy constructor could be called, and I
believe _is_ called at the formal level (the C++ abstract machine
level), but that call is optimized away by your compiler.

However, declare 'v' as const, or use a temporary, and you're no longer
in possible copy constructor call territory: _some_ constructor must be
called (although it can be optimized away), but in the case of const or
temporary auto_ptr that constructor isn't the copy constructor.

I am not getting where exactly I am going wrong.


This time it was mistaking the compiler's optimization as confirmation
of a misinterpretation of what I wrote (sorry about not being more
clear). I didn't mean that a copy constructor is never called for any
function result. I meant that a copy constructor does not always have
to be called, and in particular I meant, and wrote, that std::auto_ptr
doesn't have a ref-to-const copy constructor, which is the usual copy
constructor used for a function result.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Nov 23 '05 #4
Hello Alf,

Alf P. Steinbach wrote:
No. _Some_ constructor must be called. That call can be optimized
away, but the constructor must be available to be called (the as-if rule
for optimization).


Thanks, this clears my misunderstanding.

Continuing on my previous mail, we see that there are _two_ user
defined conversions going on one after the other in a single expression
-

1) std::auto_ptr<int> to std::auto_ptr_ref<int> by a call to
std::auto_ptr<int>operator auto_ptr_ref<int>()
2) Call to the converting constructor
std::auto_ptr<int>(std::auto_ptr_ref<int>) to create the result of type
auto_ptr<int>

If I understand right, since both of these are user defined
conversions, only one of them is allowed.

Could you please comment on this?

Nov 23 '05 #5
* Neelesh Bodas:
* Alf P. Steinbach:

No. _Some_ constructor must be called. That call can be optimized
away, but the constructor must be available to be called (the as-if rule
for optimization).


Thanks, this clears my misunderstanding.

Continuing on my previous mail, we see that there are _two_ user
defined conversions going on one after the other in a single expression
-

1) std::auto_ptr<int> to std::auto_ptr_ref<int> by a call to
std::auto_ptr<int>operator auto_ptr_ref<int>()
2) Call to the converting constructor
std::auto_ptr<int>(std::auto_ptr_ref<int>) to create the result of type
auto_ptr<int>

If I understand right, since both of these are user defined
conversions, only one of them is allowed.

Could you please comment on this?


I'd rather not... ;-)

Because it's an issue that people tend to have to agree to disagree on.

My personal take is that the second doesn't really count as a user
defined conversion because it's not a conversion producing a temporary;
it's like plugging a char const* into a std::string constructor with
direct initialization syntax (see below); no conversion has to be found
by the compiler, it's a direct match.

But that is just a convenient shovel-it-under-the-carpet-and-wave-
yer-hands-frantically explanation, because if you do

class Base {};
class Derived: public Base {};

std::auto_ptr<Base> x = std::auto_ptr<Derived>( new Derived );

then you _are_ up against the single conversion rule, and the only thing
different seems to be use of a templated constructor.

On the other hand (or is it the third, now), if you write the
initialization as a direct initialization,

std::auto_ptr<Base> x( std::auto_ptr<Derived>( new Derived ) );

then with a standard-conforming compiler all is a good (note here: MSVC
7.1 is not a standard-conforming compiler in this respect).

Perhaps someone who Really Really Knows could be kind enough to comment
on the formal "why" your point (2) isn't counted in the number of
user-defined conversions involved -- or perhaps that it is but that
the standard library is allowed to do anything, whichever is the case.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Nov 23 '05 #6
Alf P. Steinbach wrote:
then you _are_ up against the single conversion rule, and the only thing
different seems to be use of a templated constructor.


I observed a similar behaviour with a non-templated constructor also -

class Y { } ;
class X {
public:
X() { }
X (X&) { } // copy constuctor takes non-const reference
operator Y();
X(Y) { }
} ;

X foo() { X p; return p; }

int main()
{
X k = foo();
}

Here -
1) foo returns an object of type X by value. This is a temporary.
2) since this temporary cannot be passed as a reference-to-non-const,
hence the copy constructor is of no use here
3) So operator Y() is called on this temporary, and it returns another
object of type Y.
4) Now again the converting constructor X(Y) will be called and the
resulting value is put into k.

Since this is a copy initialization (and not a direct initialization),
I was thinking that this involved _two_ calls to user defined
conversion operators. But still this compiles (Comeau online, g++
3.4.2)

Nov 23 '05 #7

Neelesh Bodas wrote:
Hello All,
My question is regarding the implementation of auto pointers - How
does the class auto_ptr_ref work?

eg: suppose I have :

auto_ptr<int> foo();

int bar()
{
auto_ptr<int*> k = foo();
}


as you know, it's not possible to pass RHS "foo()" as non const
reference "auto_ptr &".
but you can call it's not const methods "foo().nonconst()".
so, "auto_ptr" use that fact to allow constructor modify RHS.

as illustration
#include<iostream>

struct auto_ptr {
int n;
static int next () { static int i; return ++i; }

struct auto_ptr_ref {
auto_ptr * ptr;
auto_ptr_ref ( auto_ptr * p ) : ptr (p) {}
};

auto_ptr () : n (next()) { std::cout << this << ":auto_ptr():new(" <<
n << ")" << std::endl; }
~auto_ptr () { std::cout << this << ":auto_ptr():delete(" << n << ")"
<< std::endl; }
auto_ptr ( auto_ptr & );
auto_ptr & operator = ( auto_ptr & );

auto_ptr ( auto_ptr_ref /*by value*/ r ) {
this->n = r.ptr->n;
r.ptr->n = 0; // update RHS
std::cout << this << ":auto_ptr(auto_ptr_ref):" << r.ptr <<
std::endl;
}
operator auto_ptr_ref () {
std::cout << this << ":operator auto_ptr_ref():" << std::endl;
return auto_ptr_ref(this);
}

};

auto_ptr foo () { auto_ptr ptr; return ptr; }

int main(){
auto_ptr ptr = foo ();
}

Nov 23 '05 #8
Hi Aleksey,
thanks for the reply.

Aleksey Loginov wrote:
auto_ptr ( auto_ptr_ref /*by value*/ r ) {
this->n = r.ptr->n;
r.ptr->n = 0; // update RHS
std::cout << this << ":auto_ptr(auto_ptr_ref):" << r.ptr <<
std::endl;
}
operator auto_ptr_ref () {
std::cout << this << ":operator auto_ptr_ref():" << std::endl;
return auto_ptr_ref(this);
}

};

auto_ptr foo () { auto_ptr ptr; return ptr; }

int main(){
auto_ptr ptr = foo ();
}


The basic reason why I am not able to understand why this works is that
I observe _two_ user defined conversions applied here -
1) conversion from auto_ptr to auto_ptr_ref using operator auto_ptr_ref
() : applied on return value of foo
2) conversion from auto_ptr_ref to auto_ptr using the constructor
auto_ptr ( auto_ptr_ref) applied on the result of 1.

The reason why I am considering (2) as a conversion is that the
initialization of ptr is done as a copy initialization - not a direct
initialization.

Or may be it is the case that (2) above is _not_ considered as a
conversion by the compiler somehow. Not sure.

Hence the confusion.

Nov 23 '05 #9
Neelesh Bodas wrote:
Hello All,
My question is regarding the implementation of auto pointers - How
does the class auto_ptr_ref work?

[snip]

See these links by N. Josuttis and S. Meyers, respectively:

http://www.josuttis.com/libbook/auto_ptr.html

http://www.awprofessional.com/conten...tr_update.html

Cheers! --M

Nov 23 '05 #10
Thanks mlimber for the reply.

Sorry for going over the same problem again, but it is really leaving
me in a confused state. Here is another confusion over the
"auto_ptr_ref" concept :

Stroustrup says in TC++PL (14.4.2) :
"The purpose of auto_ptr_ref is to implement the destructive copy
semantics for ordinary auto_ptrs while making it impossible to copy a
const auto_ptr"

Josuttis says something similar in "The C++ Std Library" -
"Fortunately, there was a late design decision that made auto_ptrs less
dangerous. By some tricky implementation techniques, transfer of
ownership is not possible with constant references. In fact, you can't
change the ownership of any constant auto_ptr:"

I havenot understood this at all. I understand that use of
auto_ptr_ref is to be able return auto_ptrs from functions and use it
on RHS or use it as argument to another function. Where does this
"Destructive copy semantics" and "impossibility to copy auto_ptrs" come
into picture? (Basically that is already guaranteed when the copy
constructor takes non-const reference as argument)

Can somebody please enlighten me on this? (It is very well possible
that I have missed out some basic points due to excessive thinking :-(
..) I have searched the net all the way, and I have already gone
through all the three drafts of auto_ptr implementation (along with the
links given by you). But I was unable to find any convincing
explanation to these issues.

Any reference which discusses design-goals of auto_ptr_ref in details
(along with examples - not just a theoretical discussion) will also be
useful.

Nov 23 '05 #11

Neelesh Bodas wrote:
Thanks mlimber for the reply.

Sorry for going over the same problem again, but it is really leaving
me in a confused state. Here is another confusion over the
"auto_ptr_ref" concept :

Stroustrup says in TC++PL (14.4.2) :
"The purpose of auto_ptr_ref is to implement the destructive copy
semantics for ordinary auto_ptrs while making it impossible to copy a
const auto_ptr"

Josuttis says something similar in "The C++ Std Library" -
"Fortunately, there was a late design decision that made auto_ptrs less
dangerous. By some tricky implementation techniques, transfer of
ownership is not possible with constant references. In fact, you can't
change the ownership of any constant auto_ptr:"

I havenot understood this at all. I understand that use of
auto_ptr_ref is to be able return auto_ptrs from functions and use it
on RHS or use it as argument to another function. Where does this
"Destructive copy semantics" and "impossibility to copy auto_ptrs" come
into picture? (Basically that is already guaranteed when the copy
constructor takes non-const reference as argument)

Can somebody please enlighten me on this? (It is very well possible
that I have missed out some basic points due to excessive thinking :-(
.) I have searched the net all the way, and I have already gone
through all the three drafts of auto_ptr implementation (along with the
links given by you). But I was unable to find any convincing
explanation to these issues.

Any reference which discusses design-goals of auto_ptr_ref in details
(along with examples - not just a theoretical discussion) will also be
useful.


Destructive copy semantics means that passing an auto_ptr around
transfers ownership, and that is precisely what distinguishes it from
boost::scoped_ptr. To achieve this design goal, Bill Gibbons and Greg
Colvin proposed the "tricky implementation" of using conversions to
auto_ptr_ref detailed at the end of the second link. Please see their
discussion in the section "Analysis of Conversion operations". If you
have specific questions about it, feel free to ask.

Cheers! --M

Nov 23 '05 #12

Neelesh Bodas wrote:
Hi Aleksey,
thanks for the reply.

Aleksey Loginov wrote:
auto_ptr ( auto_ptr_ref /*by value*/ r ) {
this->n = r.ptr->n;
r.ptr->n = 0; // update RHS
std::cout << this << ":auto_ptr(auto_ptr_ref):" << r.ptr <<
std::endl;
}
operator auto_ptr_ref () {
std::cout << this << ":operator auto_ptr_ref():" << std::endl;
return auto_ptr_ref(this);
}

};

auto_ptr foo () { auto_ptr ptr; return ptr; }

int main(){
auto_ptr ptr = foo ();
}
The basic reason why I am not able to understand why this works is that
I observe _two_ user defined conversions applied here -
1) conversion from auto_ptr to auto_ptr_ref using operator auto_ptr_ref
() : applied on return value of foo
2) conversion from auto_ptr_ref to auto_ptr using the constructor
auto_ptr ( auto_ptr_ref) applied on the result of 1.


I try to explain.
When foo returns ptr, compiler may call "auto_ptr ( auto_ptr & )" (1
step)
or "auto_ptr ( auto_ptr_ref & )" through "operator auto_ptr_ref ()" (2
steps).
First case preferred, because less steps must be done. (see Andrey's
post
http://groups.google.com/group/comp....4a47959afdddf7)
But in real, compiler allowed (and it is) not to do all that calls, and
return ptr as RHS.
The reason why I am considering (2) as a conversion is that the
initialization of ptr is done as a copy initialization - not a direct
initialization.

Or may be it is the case that (2) above is _not_ considered as a
conversion by the compiler somehow. Not sure.

Hence the confusion.


Hope this help. Sorry for dummy language.

Nov 23 '05 #13
Hello mlimber,
Please see their discussion in the section "Analysis of Conversion operations". If you
have specific questions about it, feel free to ask.
Thanks a lot for this. I read the link again, and it seems that my all
doubts have finally been answered satisfactorily.
So just thought of answering them here for others also. (please do
correct if my explanation is not appropriate)
Neelesh Bodas wrote:
The basic reason why I am not able to understand why this works is that
I observe _two_ user defined conversions applied here -
1) conversion from auto_ptr to auto_ptr_ref using operator auto_ptr_ref
() : applied on return value of foo
2) conversion from auto_ptr_ref to auto_ptr using the constructor
auto_ptr ( auto_ptr_ref) applied on the result of 1.
(2) is _not_ a conversion in this case. Quoting 8.5p14 -

"If the initialization is direct initialization, or if it is
copy-initialization where the cv-unqualified version of the source type
is the same class as, or a derived class of, the class of the
destination, constructors are considered."

Hence in the current case, when we say
std::auto_ptr<int> k = foo();
the source type ( = return type of foo() ) is std::auto_ptr<int> and
the destination type is also the same. Hence an constructor will be
considered. The only suitable constructor is
std::auto_ptr::auto_ptr(std::auto_ptr_ref).
This constructor can be called by doing a conversion from std::auto_ptr
to std::auto_ptr_ref using std::auto_ptr::operator auto_ptr_ref()
Hence there is only one user defined conversion involved, and the
constructor is called on the temporary that is the result of the
conversion.
Neelesh Bodas wrote:
4) Now since this is a copy initialization and not a direct
initialization, the RHS (whose type is now auto_ptr_ref<int>) needs to
get converted to auto_ptr<int> again - done by ctor of auto_ptr<int>
which takes auto_ptr_ref<int>
No, that is not correct.Note that the copy initialization has source
and destination types (cv -unqualified) same - and this is treated as a
special case, and it is considered differently (8.5p14), and an
initialization is possible without a call to a copy constructor.
5) Now CC should be called - but again we are back to old problem -
So no unnecessary calls to copy constructor are made in this case.
Neelesh Bodas wrote:
I observed a similar behavior with a non-templated constructor also -
int main()
{
X k = foo();
}


The same story here.

Thanks a lot to Alf, mlimber and Aleksey for their invaluable help and
insights in the problem.

Nov 23 '05 #14
In article <43*****************@news.individual.net>,
al***@start.no (Alf P. Steinbach) wrote:
Perhaps someone who Really Really Knows could be kind enough to comment
on the formal "why" your point (2) isn't counted in the number of
user-defined conversions involved -- or perhaps that it is but that
the standard library is allowed to do anything, whichever is the case.


I'm just catching up on my news reading and read through this thread
with some amusement. And I won't pretend to be able to follow all of
the twists and turns of the standard as the three of you have just done,
though I have studied it intently in the past (and perhaps even
understood it for awhile).

My reason for posting is just to point out that auto_ptr has been a very
valuable (but failed) experiment. auto_ptr has been the pioneer of
"move semantics". It is my hope that a much simpler form of move
semantics will appear in C++0X, including a (yet again) redesigned
auto_ptr under the name of unique_ptr. The new unique_ptr will do
everything auto_ptr does now (without auto_ptr_ref tricks) except one
thing: It will not move from an lvalue:

unique_ptr<int> p1;
unique_ptr<int> p2 = p1; // compile time error

However it will move from an rvalue:

unique_ptr<int> foo();

int bar()
{
unique_ptr<int> k = foo(); // ok
}

For more details see:

http://www.open-std.org/jtc1/sc22/wg...56.html#20.4.5
%20-%20Class%20template%20auto_ptr

(watch the wrap)

The most exciting thing about this (imho) is that unique_ptr is so
simple that you will easily be able to mimic its behavior in your own
classes (presumably the reason for devoting such study to auto_ptr). In
a nutshell, this is the design of unique_ptr:

template <class T>
class unique_ptr
{
public:
...
unique_ptr(unique_ptr&& u); // rvalues bind here
...
private:
unique_ptr(const unique_ptr&); // lvalues bind here
};

Once you get past the rvalue reference (&&), things just get really
simple.

-Howard
Nov 23 '05 #15

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

Similar topics

3
by: BigMan | last post by:
Here is a piece of code: #include <memory> using namespace std; template< typename SomeType > void f(auto_ptr_ref< SomeType >) { }
1
by: CID | last post by:
Hello all, I was reading about auto_ptr from TC++PL. It tells, the purpose of auto_ptr_ref is to implement the destructive copy semantics for ordinary auto_ptrs. Can somebody there please...
14
by: lutorm | last post by:
Hi, I'm having a problem with a return statement being parsed to return a function (I think). Check here: template <typename T> class A {}; template <typename T> class maker_of_A { public:...
14
by: Andrew | last post by:
Hello all: After spending some time figuring out auto_ptr class' implementation, I decided to write a small article detailing its use of the auto_ptr_ref proxy class to enable construction and...
10
by: Ivan Vecerina | last post by:
Here's a relatively simple code snippet: #include <memory> class Base { public: Base(); virtual ~Base(); virtual void f(int a, char const* name);
9
by: dragoncoder | last post by:
Hi all, I am trying to understand the auto_ptr_ref role in the implementation of auto_ptr<>. I read the information on net but still not 100% sure of it. My plan is as follows. 1. To see the...
1
by: digz | last post by:
Hi, The std::auto_ptr 14.4.2 in Stroustrup ,the book talks about "std::auto_pt_ref is to implement destructive copy semantics" , after some more search I found that auto_ptr can be returned from...
18
by: Barry | last post by:
struct A { void Print() const { cout << "Print" << endl; } }; auto_ptr<AGet() {
4
by: james.lawton | last post by:
Hi, I'm having a problem that I can't diagnose. I'm creating istreams of unknown types, and want to manage them on the stack, co I'm passing around ownership-holding pointers. Usually, I would...
0
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
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
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
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
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
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
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
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
muto222
php
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.