A strange compiler error C2440
-
Here is my program.I compile it in Visual C++ .Net(VC7) and get a C2440:
// All needed headers were included. #include "stdafx.h" using namespace std; class b { protected: int id; public: b( int i ) : id(i) { cout << "ctor of id:" << id << " was called." << endl; } ~b() { cout << "dtor of id:" << id << " was called." << endl; } b( const b & x) : id(x.id) { } const b operator=( const b & x ) { id=x.id; return *this; } }; typedef auto_ptr<b> pb; typedef vector<pb> vpb; int main( void ) { pb t(new b(1)); vpb v; v.push_back( t );// //error C2440: 'initializing' : cannot convert from 'const pb' to 'std::auto_ptr<_Ty>' with [ _Ty=b ] return 0; }
Is it a bug of VC7 or anything wrong in my codes? You don't know what you've got till it's gone. -
Here is my program.I compile it in Visual C++ .Net(VC7) and get a C2440:
// All needed headers were included. #include "stdafx.h" using namespace std; class b { protected: int id; public: b( int i ) : id(i) { cout << "ctor of id:" << id << " was called." << endl; } ~b() { cout << "dtor of id:" << id << " was called." << endl; } b( const b & x) : id(x.id) { } const b operator=( const b & x ) { id=x.id; return *this; } }; typedef auto_ptr<b> pb; typedef vector<pb> vpb; int main( void ) { pb t(new b(1)); vpb v; v.push_back( t );// //error C2440: 'initializing' : cannot convert from 'const pb' to 'std::auto_ptr<_Ty>' with [ _Ty=b ] return 0; }
Is it a bug of VC7 or anything wrong in my codes? You don't know what you've got till it's gone.Only a shot in the dark (don't have my docs at hand): I assume
vector::push_back()
takes a const reference to the object type (which is auto_ptr<b> in your case). An auto_ptr contains an ownership flag and if assigning auto_ptrs always the L-value takes ownership. For this the R-value (the auto_ptr you try to insert in your vector) has to be modified, because it's ownerhip flag has to be cleared. And this is not possible because it has been passed as a const reference. The error message could be translated to:error C2440: 'initializing' : cannot convert from 'const std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty>' with [ _Ty=b ]
which makes the problem a bit more obvious. (BTW: Does anybody know why the the C++ standard comitee did not made the ownership flag of an auto_ptr mutable, so it could be modified even in const objects?) -- Daniel Lohmann http://www.losoft.de (Hey, this page is worth looking! You can find some free and handy NT tools there :-D ) -
Only a shot in the dark (don't have my docs at hand): I assume
vector::push_back()
takes a const reference to the object type (which is auto_ptr<b> in your case). An auto_ptr contains an ownership flag and if assigning auto_ptrs always the L-value takes ownership. For this the R-value (the auto_ptr you try to insert in your vector) has to be modified, because it's ownerhip flag has to be cleared. And this is not possible because it has been passed as a const reference. The error message could be translated to:error C2440: 'initializing' : cannot convert from 'const std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty>' with [ _Ty=b ]
which makes the problem a bit more obvious. (BTW: Does anybody know why the the C++ standard comitee did not made the ownership flag of an auto_ptr mutable, so it could be modified even in const objects?) -- Daniel Lohmann http://www.losoft.de (Hey, this page is worth looking! You can find some free and handy NT tools there :-D )You're dead right - it's because the auto_ptr copy constructor takes a non-const reference. The reason it's like that (i.e. not using mutable on the ownership flag) is that containers require that their content elements can be copied without altering the element being copied. For example (and I'm quoting Herb Sutter's Exceptional C++), sort algorithms (particularly those based on partitioning & sorting, I suspect) take copies of elements of containers. This would result in the element being deleted, but it's reference still being in the container.
auto_ptr
is really best used as a scoped pointer container, i.e. without transfer of ownership. It does help make things easier then, especially with helping to ensure exception safety. Stuart Dootson 'Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p' -
Only a shot in the dark (don't have my docs at hand): I assume
vector::push_back()
takes a const reference to the object type (which is auto_ptr<b> in your case). An auto_ptr contains an ownership flag and if assigning auto_ptrs always the L-value takes ownership. For this the R-value (the auto_ptr you try to insert in your vector) has to be modified, because it's ownerhip flag has to be cleared. And this is not possible because it has been passed as a const reference. The error message could be translated to:error C2440: 'initializing' : cannot convert from 'const std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty>' with [ _Ty=b ]
which makes the problem a bit more obvious. (BTW: Does anybody know why the the C++ standard comitee did not made the ownership flag of an auto_ptr mutable, so it could be modified even in const objects?) -- Daniel Lohmann http://www.losoft.de (Hey, this page is worth looking! You can find some free and handy NT tools there :-D )You're right. The error message confused me. I thought the compiler cannot translate 'pb' to 'std::auto_ptr<_Ty>' or doesn't support nested templates or anything like that. It seems I should provide a const constructor for auto_ptr by myself. Thanks.:) -------------------------------- You don't know what you've got till it's gone.
-
Only a shot in the dark (don't have my docs at hand): I assume
vector::push_back()
takes a const reference to the object type (which is auto_ptr<b> in your case). An auto_ptr contains an ownership flag and if assigning auto_ptrs always the L-value takes ownership. For this the R-value (the auto_ptr you try to insert in your vector) has to be modified, because it's ownerhip flag has to be cleared. And this is not possible because it has been passed as a const reference. The error message could be translated to:error C2440: 'initializing' : cannot convert from 'const std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty>' with [ _Ty=b ]
which makes the problem a bit more obvious. (BTW: Does anybody know why the the C++ standard comitee did not made the ownership flag of an auto_ptr mutable, so it could be modified even in const objects?) -- Daniel Lohmann http://www.losoft.de (Hey, this page is worth looking! You can find some free and handy NT tools there :-D )... // in the header <vector> void _Insert_n(iterator _Where, size_type _Count, const _Ty& _Val) { // insert _Count * _Val at _Where _Ty _Tmp = _Val; // in case _Val is in sequence // C2440 was actually raised here size_type _Capacity = capacity(); ...
It seems that the compiler could not find the operator=, but a copy constructor and the operator= have been present in the header :template<class _Ty> class auto_ptr { // wrap an object pointer to ensure destruction public: typedef _Ty element_type; explicit auto_ptr(_Ty *_Ptr = 0) _THROW0() : _Myptr(_Ptr) { // construct from object pointer } auto_ptr(auto_ptr<_Ty>& _Right) _THROW0() : _Myptr(_Right.release()) { // construct by assuming pointer from _Right auto_ptr } auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0() : _Myptr(_Right._Ref.release()) { // construct by assuming pointer from _Right auto_ptr_ref } ... auto_ptr<_Ty>& operator=(auto_ptr<_Ty>& _Right) _THROW0() { // assign compatible _Right (assume pointer) reset(_Right.release()); return (*this); } ...
The compiler just ignored them. ------------- You don't know what you've got till it's gone. -
You're right. The error message confused me. I thought the compiler cannot translate 'pb' to 'std::auto_ptr<_Ty>' or doesn't support nested templates or anything like that. It seems I should provide a const constructor for auto_ptr by myself. Thanks.:) -------------------------------- You don't know what you've got till it's gone.
Be careful later ! dlhson2001@yahoo.com
-
You're dead right - it's because the auto_ptr copy constructor takes a non-const reference. The reason it's like that (i.e. not using mutable on the ownership flag) is that containers require that their content elements can be copied without altering the element being copied. For example (and I'm quoting Herb Sutter's Exceptional C++), sort algorithms (particularly those based on partitioning & sorting, I suspect) take copies of elements of containers. This would result in the element being deleted, but it's reference still being in the container.
auto_ptr
is really best used as a scoped pointer container, i.e. without transfer of ownership. It does help make things easier then, especially with helping to ensure exception safety. Stuart Dootson 'Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p'Thanks Stuart, that surly makes sense and is, if one thinks a bit about it, rather obvious. -- Daniel Lohmann http://www.losoft.de (Hey, this page is worth looking! You can find some free and handy NT tools there :-D )
-
... // in the header <vector> void _Insert_n(iterator _Where, size_type _Count, const _Ty& _Val) { // insert _Count * _Val at _Where _Ty _Tmp = _Val; // in case _Val is in sequence // C2440 was actually raised here size_type _Capacity = capacity(); ...
It seems that the compiler could not find the operator=, but a copy constructor and the operator= have been present in the header :template<class _Ty> class auto_ptr { // wrap an object pointer to ensure destruction public: typedef _Ty element_type; explicit auto_ptr(_Ty *_Ptr = 0) _THROW0() : _Myptr(_Ptr) { // construct from object pointer } auto_ptr(auto_ptr<_Ty>& _Right) _THROW0() : _Myptr(_Right.release()) { // construct by assuming pointer from _Right auto_ptr } auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0() : _Myptr(_Right._Ref.release()) { // construct by assuming pointer from _Right auto_ptr_ref } ... auto_ptr<_Ty>& operator=(auto_ptr<_Ty>& _Right) _THROW0() { // assign compatible _Right (assume pointer) reset(_Right.release()); return (*this); } ...
The compiler just ignored them. ------------- You don't know what you've got till it's gone.Did you read the posting of Stuart to this topic? It is nearly impossible to use auto_ptr in STL containers (and any other kind of container), because you run into a bunch of problems :( -- Daniel Lohmann http://www.losoft.de (Hey, this page is worth looking! You can find some free and handy NT tools there :-D )
-
... // in the header <vector> void _Insert_n(iterator _Where, size_type _Count, const _Ty& _Val) { // insert _Count * _Val at _Where _Ty _Tmp = _Val; // in case _Val is in sequence // C2440 was actually raised here size_type _Capacity = capacity(); ...
It seems that the compiler could not find the operator=, but a copy constructor and the operator= have been present in the header :template<class _Ty> class auto_ptr { // wrap an object pointer to ensure destruction public: typedef _Ty element_type; explicit auto_ptr(_Ty *_Ptr = 0) _THROW0() : _Myptr(_Ptr) { // construct from object pointer } auto_ptr(auto_ptr<_Ty>& _Right) _THROW0() : _Myptr(_Right.release()) { // construct by assuming pointer from _Right auto_ptr } auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0() : _Myptr(_Right._Ref.release()) { // construct by assuming pointer from _Right auto_ptr_ref } ... auto_ptr<_Ty>& operator=(auto_ptr<_Ty>& _Right) _THROW0() { // assign compatible _Right (assume pointer) reset(_Right.release()); return (*this); } ...
The compiler just ignored them. ------------- You don't know what you've got till it's gone.Noooo - not quite. If you look at the vector definition,
void _Insert_n(iterator _Where, size_type _Count, **const** _Ty& _Val)
, it takes a const reference. BUT - inauto_ptr
, none of the assignment operators/coy constructors take a const reference parameter. As you cannot implicitly convert const to non-const, the compiler cannot use these operators! It is that simple really, honest!:) Stuart Dootson 'Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p' -
Here is my program.I compile it in Visual C++ .Net(VC7) and get a C2440:
// All needed headers were included. #include "stdafx.h" using namespace std; class b { protected: int id; public: b( int i ) : id(i) { cout << "ctor of id:" << id << " was called." << endl; } ~b() { cout << "dtor of id:" << id << " was called." << endl; } b( const b & x) : id(x.id) { } const b operator=( const b & x ) { id=x.id; return *this; } }; typedef auto_ptr<b> pb; typedef vector<pb> vpb; int main( void ) { pb t(new b(1)); vpb v; v.push_back( t );// //error C2440: 'initializing' : cannot convert from 'const pb' to 'std::auto_ptr<_Ty>' with [ _Ty=b ] return 0; }
Is it a bug of VC7 or anything wrong in my codes? You don't know what you've got till it's gone.Futher to my other replies - if you want to use smart pointers in STL containers, I'd suggest you use the Boost
shared_ptr
class. Go to www.boost.org[^]. There's a download for the whole library there. There's a whole lot more than just smart pointers as well... Stuart Dootson 'Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p' -
Here is my program.I compile it in Visual C++ .Net(VC7) and get a C2440:
// All needed headers were included. #include "stdafx.h" using namespace std; class b { protected: int id; public: b( int i ) : id(i) { cout << "ctor of id:" << id << " was called." << endl; } ~b() { cout << "dtor of id:" << id << " was called." << endl; } b( const b & x) : id(x.id) { } const b operator=( const b & x ) { id=x.id; return *this; } }; typedef auto_ptr<b> pb; typedef vector<pb> vpb; int main( void ) { pb t(new b(1)); vpb v; v.push_back( t );// //error C2440: 'initializing' : cannot convert from 'const pb' to 'std::auto_ptr<_Ty>' with [ _Ty=b ] return 0; }
Is it a bug of VC7 or anything wrong in my codes? You don't know what you've got till it's gone.You know this code will crash and burn? Don't ever use auto_ptr in collections. Have a look at some other pointer type such as shared_ptr from the BOOST library.