By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,412 Members | 993 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,412 IT Pros & Developers. It's quick & easy.

auto_ptr who is right?

P: n/a
struct A
{
void Print() const {
cout << "Print" << endl;
}
};
auto_ptr<AGet()
{
new A; // (1)
// auto_ptr<A>(new A); // (2) works fine
}

int main()
{
auto_ptr<Ap = Get();
p->Print();
}

if use MSVC8.0 it crash, turns out what p contains is a null pointer
if use STLPort, it works fine,

So is there something wrong with the code, or with MSVC8.0
implementation of auto_ptr ?
--
Thanks
Barry
Sep 2 '07 #1
Share this Question
Share on Google+
18 Replies


P: n/a
On 2 Sep., 15:19, Barry <dhb2...@gmail.comwrote:
struct A
{
void Print() const {
cout << "Print" << endl;
}

};

auto_ptr<AGet()
{
new A; // (1)
// auto_ptr<A>(new A); // (2) works fine
Don't you respect your compilers warnings? This should not compile
without a warning, and you do not return anything - whats returned is
rubbish.
}

int main()
{
auto_ptr<Ap = Get();
p->Print();
Here you dereference garbage. Garbage in means garbase out.

/Peter

[snip]

Sep 2 '07 #2

P: n/a
peter koch wrote:
On 2 Sep., 15:19, Barry <dhb2...@gmail.comwrote:
>struct A
{
void Print() const {
cout << "Print" << endl;
}

};

auto_ptr<AGet()
{
new A; // (1)
// auto_ptr<A>(new A); // (2) works fine

Don't you respect your compilers warnings? This should not compile
without a warning, and you do not return anything - whats returned is
rubbish.
sorry, I didn't compile this code, I just make a mimic example
after I post this thread, I compile this code (add return), and found it
work also on MSVC8
>}

int main()
{
auto_ptr<Ap = Get();
p->Print();
Here you dereference garbage. Garbage in means garbase out.

/Peter

[snip]
Well, this one really crashes!

#include <memory>
#include <iostream>
#include <string>

using namespace std;

struct Pizza
{
Pizza(string const& name) : name_(name) {}
void Show() const
{
cout << name_ << " Pizza" << endl;
}
private:
string name_;
};

struct Pie
{
Pie(string const& name) : name_(name) {}
void Show() const
{
cout << name_ << " Pie" << endl;
}
private:
string name_;
};

class AbstractFactory
{
public:
virtual auto_ptr<PizzaCreatePizza() = 0;

virtual ~AbstractFactory() {}
};

class NestFactory
: public AbstractFactory
{
virtual auto_ptr<PizzaCreatePizza()
{
return new Pizza("Nest");
}
};

int main()
{
auto_ptr<AbstractFactorypFactory(new NestFactory);
auto_ptr<PizzapPizza = pFactory->CreatePizza();
pPizza->Show();
}

--
Thanks
Barry
Sep 2 '07 #3

P: n/a

Barry <dh*****@gmail.comwrote in message...
>
sorry, I didn't compile this code, I just make a mimic example
after I post this thread, I compile this code (add return), and found it
work also on MSVC8
Well, this one really crashes!

#include <memory>
#include <iostream>
#include <string>
using namespace std;

struct Pizza{
Pizza(string const& name) : name_(name) {}
void Show() const {
cout << name_ << " Pizza" << endl;
}
private:
string name_;
};
<snip unused 'Pie' >
class AbstractFactory{ public:
virtual auto_ptr<PizzaCreatePizza() = 0;
virtual ~AbstractFactory() {}
};

class NestFactory : public AbstractFactory {
virtual auto_ptr<PizzaCreatePizza(){
// return new Pizza( "Nest" );
// error: conversion from `Pizza*' to non-scalar type
// `std::auto_ptr<Pizza>' requested

return std::auto_ptr<Pizza>( new Pizza( "Nest" ) );
}
};

int main(){
auto_ptr<AbstractFactorypFactory(new NestFactory);
auto_ptr<PizzapPizza = pFactory->CreatePizza();
pPizza->Show();
}
--
Bob R
POVrookie
Sep 3 '07 #4

P: n/a
BobR wrote:
Barry <dh*****@gmail.comwrote in message...
>sorry, I didn't compile this code, I just make a mimic example
after I post this thread, I compile this code (add return), and found it
work also on MSVC8
Well, this one really crashes!

#include <memory>
#include <iostream>
#include <string>
using namespace std;

struct Pizza{
Pizza(string const& name) : name_(name) {}
void Show() const {
cout << name_ << " Pizza" << endl;
}
private:
string name_;
};
<snip unused 'Pie' >
>class AbstractFactory{ public:
virtual auto_ptr<PizzaCreatePizza() = 0;
virtual ~AbstractFactory() {}
};

class NestFactory : public AbstractFactory {
virtual auto_ptr<PizzaCreatePizza(){

// return new Pizza( "Nest" );
// error: conversion from `Pizza*' to non-scalar type
// `std::auto_ptr<Pizza>' requested

return std::auto_ptr<Pizza>( new Pizza( "Nest" ) );
Thanks for your reply, can you tell me where in the standard talk about
this?

And more, why the example in the OP works with MSVC8 while this one does
NOT?
And why all cases works well with STLPort? Is this a bug in STLPort's
auto_ptr?
>
> }
};

int main(){
auto_ptr<AbstractFactorypFactory(new NestFactory);
auto_ptr<PizzapPizza = pFactory->CreatePizza();
pPizza->Show();
}

--
Thanks
Barry
Sep 3 '07 #5

P: n/a

Barry <dh***@126.comwrote in message...
BobR wrote:

return std::auto_ptr<Pizza>( new Pizza( "Nest" ) );

Thanks for your reply, can you tell me where in the standard talk about
this?

And more, why the example in the OP works with MSVC8 while this one does
NOT?
It does NOT work. Did you read what Peter said?

You can't return an object A pointer where it is expected to return an
std::auto_ptr object. If it does compile and run, it's UB.
What you were trying to do is akin to:
std::string Line("Hello World!");
int Number = Line;
And why all cases works well with STLPort? Is this a bug in STLPort's
auto_ptr?
You'll have to ask that where you got STLPort.

Does this compile for you?

// includes here
struct Pizza{
Pizza( std::string const& name) : name_(name) {}
void Show( std::ostream &out ) const {
out<<name_<<" Pizza"<<std::endl;
}
private:
std::string name_;
};

class AbstractFactory{ public:
virtual std::auto_ptr<PizzaCreatePizza() = 0;
virtual Pizza* CreatePizza2() = 0;
virtual ~AbstractFactory() {}
};

class NestFactory : public AbstractFactory{
virtual std::auto_ptr<PizzaCreatePizza(){
return std::auto_ptr<Pizza>( new Pizza( "Nest" ) );
}
virtual Pizza* CreatePizza2(){
return new Pizza( "Nest2" );
}
};

int main(){
std::auto_ptr<AbstractFactorypFactory( new NestFactory );
std::auto_ptr<PizzapPizza = pFactory->CreatePizza();
pPizza->Show( std::cout );
std::auto_ptr<PizzapPizza2( pFactory->CreatePizza2() );
pPizza2->Show( std::cout );
return 0;
} // main()

--
Bob R
POVrookie
Sep 3 '07 #6

P: n/a
BobR wrote:
Barry <dh***@126.comwrote in message...
>BobR wrote:
>> return std::auto_ptr<Pizza>( new Pizza( "Nest" ) );
Thanks for your reply, can you tell me where in the standard talk about
this?

And more, why the example in the OP works with MSVC8 while this one does
NOT?

It does NOT work. Did you read what Peter said?

You can't return an object A pointer where it is expected to return an
std::auto_ptr object. If it does compile and run, it's UB.
What you were trying to do is akin to:
std::string Line("Hello World!");
int Number = Line;
>And why all cases works well with STLPort? Is this a bug in STLPort's
auto_ptr?

You'll have to ask that where you got STLPort.

Does this compile for you?

// includes here
struct Pizza{
Pizza( std::string const& name) : name_(name) {}
void Show( std::ostream &out ) const {
out<<name_<<" Pizza"<<std::endl;
}
private:
std::string name_;
};

class AbstractFactory{ public:
virtual std::auto_ptr<PizzaCreatePizza() = 0;
virtual Pizza* CreatePizza2() = 0;
virtual ~AbstractFactory() {}
};

class NestFactory : public AbstractFactory{
virtual std::auto_ptr<PizzaCreatePizza(){
return std::auto_ptr<Pizza>( new Pizza( "Nest" ) );
}
virtual Pizza* CreatePizza2(){
return new Pizza( "Nest2" );
}
};

int main(){
std::auto_ptr<AbstractFactorypFactory( new NestFactory );
std::auto_ptr<PizzapPizza = pFactory->CreatePizza();
pPizza->Show( std::cout );
std::auto_ptr<PizzapPizza2( pFactory->CreatePizza2() );
pPizza2->Show( std::cout );
return 0;
} // main()
I think it's not that simple as

string Line("dsdsd");
int i = Line;
with auto_ptr

See from the code of auto_ptr from Dinkumware,
it has a explicit constructor
so the return statement find auto_ptr_ref(void*) to construct auto_ptr
then take this auto_ptr_ref to construct auto_ptr.
that's why the code compiles.

but I didn't see anything about the conversion between auto_ptr_ref and
auto_ptr, it seems to be implementation defined.

So what I want to find out is

template <class T>
auto_ptr<TGetT()
{
return new T;
}

is legal or not? or it's just implementation defined which depends on
the implementation of auto_ptr_ref

--
Thanks
Barry
Sep 3 '07 #7

P: n/a
On Sep 3, 12:23 am, Barry <dh...@126.comwrote:
So what I want to find out is

template <class T>
auto_ptr<TGetT()
{
return new T;

}

is legal or not? or it's just implementation defined which depends on
the implementation of auto_ptr_ref
There is no implicit conversion from a T* to an auto_ptr<T>, because
the auto_ptr constructor that would perform the implicit conversion is
declared "explicit". Therefore, a function returning an auto_ptr must
construct its return value explicitly - as the CreatePizza() routine
that BobR posted, demonstrated:

template <class T>
auto_ptr<TGetT()
{
return auto_ptr<T>(new T);
}

Greg
Sep 3 '07 #8

P: n/a
Greg Herlihy wrote:
On Sep 3, 12:23 am, Barry <dh...@126.comwrote:
>So what I want to find out is

template <class T>
auto_ptr<TGetT()
{
return new T;

}

is legal or not? or it's just implementation defined which depends on
the implementation of auto_ptr_ref

There is no implicit conversion from a T* to an auto_ptr<T>, because
the auto_ptr constructor that would perform the implicit conversion is
declared "explicit". Therefore, a function returning an auto_ptr must
construct its return value explicitly - as the CreatePizza() routine
that BobR posted, demonstrated:

template <class T>
auto_ptr<TGetT()
{
return auto_ptr<T>(new T);
}
Well, when I step into the code with MSVC8, the construction path is
T* -auto_ptr_ref -auto_ptr
which is done implicitly by the compiler, which is not user-expected.
And because auto_ptr_ref is made to hold ref of auto_ptr, not the
pointer itself, so the construction path is ill formed though it
compiles this way.

--
Thanks
Barry
Sep 3 '07 #9

P: n/a
Greg Herlihy wrote:
On Sep 3, 12:23 am, Barry <dh...@126.comwrote:
>So what I want to find out is

template <class T>
auto_ptr<TGetT()
{
return new T;

}

is legal or not? or it's just implementation defined which depends on
the implementation of auto_ptr_ref

There is no implicit conversion from a T* to an auto_ptr<T>, because
the auto_ptr constructor that would perform the implicit conversion is
declared "explicit". Therefore, a function returning an auto_ptr must
construct its return value explicitly - as the CreatePizza() routine
that BobR posted, demonstrated:

template <class T>
auto_ptr<TGetT()
{
return auto_ptr<T>(new T);
}

Greg

Sorry, My bad,
The MSVC8 is broken to report the compile error

#include <memory>

struct A;

struct A_cvt
{
A_cvt(int i)
{
}
};

struct A
{
explicit A(int i) {}
A(A_cvt rhs) {}
};

A GetA()
{
return 1;
}

int main()
{
}

It DO compile the code above. So it makes a construction path
T* -auto_ptr_ref -auto_ptr.
which makes me blur about the *explicit* keyword.

--
Thanks
Barry
Sep 3 '07 #10

P: n/a
Hi!

Barry schrieb:
It DO compile the code above. So it makes a construction path
T* -auto_ptr_ref -auto_ptr.
which makes me blur about the *explicit* keyword.
Any construction path must not include more than _ONE_ implicit
conversion by constructor. Thus the path is illegal and MSVC is wrong.

Frank
Sep 3 '07 #11

P: n/a
On Sep 3, 7:09 am, Frank Birbacher <bloodymir.c...@gmx.netwrote:
Hi!

Barry schrieb:
It DO compile the code above. So it makes a construction path
T* -auto_ptr_ref -auto_ptr.
which makes me blur about the *explicit* keyword.

Any construction path must not include more than _ONE_ implicit
conversion by constructor. Thus the path is illegal and MSVC is wrong.

Frank
I also ran into this issue.
It can be avoided if not using MS compiler extensions.
BUT... you have to give up on your <windowsheader :(

I want a clean solution to this problem, too.

Diego
HP

Sep 3 '07 #12

P: n/a
Hello,
I have to use Visual Studio 2005 at work:-(. Think, MSVC8 is the
associated compiler.
For me auto_ptr of MSVC was broken. Some static cast instead of the
right dynamic one.
Makes polymorphic use impossible. Maybe, this is fixed in your version
of MSVC.
Best regards,
Tobias

Sep 3 '07 #13

P: n/a
Hi!

Tobias schrieb:
I have to use Visual Studio 2005 at work:-(. Think, MSVC8 is the
associated compiler.
For me auto_ptr of MSVC was broken. Some static cast instead of the
right dynamic one.
Makes polymorphic use impossible. Maybe, this is fixed in your version
of MSVC.
MSVC8 is currently the latest (released) compiler. Could you provide a
little program to show the error?

Frank
Sep 3 '07 #14

P: n/a
Tobias wrote:
Hello,
I have to use Visual Studio 2005 at work:-(. Think, MSVC8 is the
associated compiler.
For me auto_ptr of MSVC was broken. Some static cast instead of the
right dynamic one.
Makes polymorphic use impossible. Maybe, this is fixed in your version
of MSVC.
Best regards,
Tobias
Well,
as I test the code on the Dinkumware Exam
http://www.dinkumware.com/exam/default.aspx
All the VC series produce the right compile error against auto_ptr,
except VC6, which is forgivable. so maybe there's already some Service Pack.
Sep 4 '07 #15

P: n/a
// MSVC8 is currently the latest (released) compiler. Could you
provide a
// little program to show the error?
// Try this one with MSVC++ 8.0 and g++ 3.4.4 (or later).
// If both give the same results the error is fixed in your version of
MSVC++.
// If the VC++-Version calls A1::f() this is the error.
// In that case (as I've already mentioned) there is a wrong static
cast in <memory>.

#include<memory>
#include<fstream>

std::ofstream log;

struct A1
{
A1() {
log << "A1::A1()\n";
}

virtual void f() {
log << "A1::f() should never be called.\n";
}

virtual ~A1() {
log << "A1::~A1()\n";
}
};

struct A2
{
A2() {
log << "A2::A2()\n";
}

virtual void g() {
log << "A2::g() should be called the first time.\n";
}

virtual ~A2() {
log << "A2::~A2()\n";
}
};

struct B: public A1, public A2
{
B() {
log << "B::B()\n";
}

virtual void g() {
log << "B::g() should be called the second time.\n";
}

virtual ~B() {
log << "B::~B()\n";
}
};

void f(bool b)
{
std::auto_ptr<A2pA2;

if(b)
pA2 = std::auto_ptr<B>(new B());
else
pA2 = std::auto_ptr<A2>(new A2());

pA2->g();
}

int main()
{
log.open("log");
if(!log) return -1;

f(false);
f(true);

log.close();
return 0;
}
Sep 4 '07 #16

P: n/a
Tobias wrote:
// MSVC8 is currently the latest (released) compiler. Could you
provide a
// little program to show the error?
// Try this one with MSVC++ 8.0 and g++ 3.4.4 (or later).
// If both give the same results the error is fixed in your version of
MSVC++.
// If the VC++-Version calls A1::f() this is the error.
// In that case (as I've already mentioned) there is a wrong static
cast in <memory>.
i didn't find the cast you mentioned.
where?
>
void f(bool b)
{
std::auto_ptr<A2pA2;

if(b)
pA2 = std::auto_ptr<B>(new B());
actually here should've called

template<class Yauto_ptr& operator=(auto_ptr<Y>&) throw(); // 20.4.5.1
construct/copy/destroy:

instead of constructing auto_ptr_ref, then
auto_ptr& operator=(auto_ptr_ref<Xr) throw();

It seems auto_ptr_ref in MSVC8 interferes too much
else
pA2 = std::auto_ptr<A2>(new A2());

pA2->g();
}


--
Thanks
Barry
Sep 5 '07 #17

P: n/a
Barry wrote:
i didn't find the cast you mentioned.
where?
Maybe, I should have said `old-style-cast´ instead of `static cast´
since there is no literal `static_cast´ in <memory>. But the effect is
the same.

Bad things happen in the following snippet of the VC++ version of
<memory>:

8<
template<class _Other>
operator auto_ptr_ref<_Other>() _THROW0()
{ // convert to compatible auto_ptr_ref
_Other *_Testptr = (_Ty *)_Myptr; // test implicit conversion
auto_ptr_ref<_Other_Ans(&_Myptr);
return (_Testptr != 0 ? _Ans : _Ans);
}
>8
8<
template<class _Ty>
struct auto_ptr_ref
{ // proxy reference for auto_ptr copying
auto_ptr_ref(void *_Right)
: _Ref(_Right)
{ // construct from generic pointer to auto_ptr ptr
}

void *_Ref; // generic pointer to auto_ptr ptr
};
>8
Outch! After some test of object-compatibility the object pointer is
reduced to a void* pointer for later usage. This only works if the
vtable is quite simple. If I'm not mistaken the start of the vtable of
the base class must be equal to the start of the vtable of the derived
class. That is not always the case as we have seen in the example.

It looks better in <memoryof g++:
8<
template<typename _Tp1>
operator auto_ptr_ref<_Tp1>() throw()
{ return auto_ptr_ref<_Tp1>(this->release()); }
>8
8<
template<typename _Tp1>
struct auto_ptr_ref
{
_Tp1* _M_ptr;

explicit
auto_ptr_ref(_Tp1* __p): _M_ptr(__p) { }
};
>8
Regards,
Tobias

Sep 5 '07 #18

P: n/a
Tobias wrote:
8<
template<class _Ty>
struct auto_ptr_ref
{ // proxy reference for auto_ptr copying
auto_ptr_ref(void *_Right)
: _Ref(_Right)
{ // construct from generic pointer to auto_ptr ptr
}

void *_Ref; // generic pointer to auto_ptr ptr
};
>8

Outch! After some test of object-compatibility the object pointer is
reduced to a void* pointer for later usage. This only works if the
vtable is quite simple. If I'm not mistaken the start of the vtable of
the base class must be equal to the start of the vtable of the derived
class. That is not always the case as we have seen in the example.
well, it's a mayor bug also inside auto_ptr implementation in MSVC8
the void* is already changed into Ty* in the VC9 beta. It's seems all
the cases here works fine with it.

anyway, it still uses auto_ptr_ref conversion in your case other than
template<class Yauto_ptr& operator=(auto_ptr<Y>&) throw();

it's painful using auto_ptr at least with MSVC, while I felt that I'm
defending it.
It's deprecated in the working draft, said that it will be replaced by
unique_ptr, which borrows the new `Move' syntex. Still a long time to wait.

--
Thanks
Barry
Sep 6 '07 #19

This discussion thread is closed

Replies have been disabled for this discussion.