Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien
Toon posts:

[C++] Issue met auto_ptr copy constructor (VC++6 --> VS2008)

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hallo C++/Template Gurus,

Ik ben momenteel bezig om oude obscure 3rd party code (bouwbaar in Visual C++ 6) om te zetten naar VS2008/2010. In de nieuwere compilers zijn een aantal C++ regels veel strikter gemaakt.
Nu is het meeste vrij eenvoudig gegaan, maar helaas ben ik vastgelopen in een stukje van template van auto pointer, en wel dat de compiler klaagt over de copy constructor.

Originele VC++ 6.0 code (regel 14 geeft het probleem):
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
File: my_auto_ptr.h

#ifndef __MY_AUTO_PTR_H
#define __MY_AUTO_PTR_H

#include <vector>
template <class T>
class my_auto_ptr : public std::auto_ptr<T>
{
public:
    my_auto_ptr() : std::auto_ptr<T>(){}
    my_auto_ptr(T* p):std::auto_ptr<T>(p){}

    my_auto_ptr(const my_auto_ptr & lp) 
        :std::auto_ptr<T>(lp){ }

    bool operator < (const std::auto_ptr<T> &pt) const { return *get() < *pt ;}
    bool operator == (const std::auto_ptr<T> &pt) const { return *get() == *pt ;}
};
#endif


De compiler struikelt over de copy constructor in regel 14 en wel met de volgende melding:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1>c:\.....\my_auto_ptr.h(19) : error C2664: 'std::auto_ptr<_Ty>::auto_ptr<T>(std::auto_ptr<_Ty> &) throw()' : cannot convert parameter 1 from 'const my_auto_ptr<T>' to 'std::auto_ptr<_Ty> &'
1>        with
1>        [
1>            _Ty=CLine,
1>            T=CLine
1>        ]
1>        and
1>        [
1>            T=CLine
1>        ]
1>        and
1>        [
1>            _Ty=CLine
1>        ]
1>        Conversion loses qualifiers
1>        c:\.....\my_auto_ptr.h(19) : while compiling class template member function 'my_auto_ptr<T>::my_auto_ptr(const my_auto_ptr<T> &)'
1>        with
1>        [
1>            T=CLine
1>        ]
1>        C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afxtempl.h(1257) : see reference to class template instantiation 'my_auto_ptr<T>' being compiled
1>        with
1>        [
1>            T=CLine
1>        ]
enzovoorts...


Ik loop hier helaas een beetje stuk...
Hebben jullie een hint/suggestie?

Thx

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

auto_ptr copy constructor wijzigt het argument, dus je kan niet const auto_ptr & gebruiken als argument (dat is hoe een auto_ptr werkt), haal je const keyword weg op regel 14 en het compiled waarschijnlijk.

los daar van, die hele class is onzinnig, het is een wrapper om de halve functionaliteit.

[ Voor 38% gewijzigd door MLM op 06-04-2011 19:38 ]

-niks-


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17:31

.oisyn

Moderator Devschuur®

Demotivational Speaker

operator==() zal ook áltijd false geven bij auto_ptr. Er kan immers maar 1 auto_ptr zijn met die pointer.

auto_ptr is sowieso obsolete. Kijk anders eens naar std::tr1::shared_ptr en unique_ptr.

[ Voor 30% gewijzigd door .oisyn op 06-04-2011 23:35 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
MLM schreef op woensdag 06 april 2011 @ 19:36:
auto_ptr copy constructor wijzigt het argument, dus je kan niet const auto_ptr & gebruiken als argument (dat is hoe een auto_ptr werkt), haal je const keyword weg op regel 14 en het compiled waarschijnlijk.

los daar van, die hele class is onzinnig, het is een wrapper om de halve functionaliteit.
.oisyn schreef op woensdag 06 april 2011 @ 23:34:
operator==() zal ook áltijd false geven bij auto_ptr. Er kan immers maar 1 auto_ptr zijn met die pointer.

auto_ptr is sowieso obsolete. Kijk anders eens naar std::tr1::shared_ptr en unique_ptr.
Jullie hebben beiden gelijk over de dat onzinnige + obsolete.
Punt is alleen...
Je wilt zo weinig mogelijk bestaande (werkende) modules aanpassen. Zeker als het niet uit je eigen keuken komt. Dit om 'olievlek' problemen te voorkomen.

Die van de const weglaten was inderdaad een logische stap, ware het niet een andere error oplevert...
Een "no copy constructor available or copy constructor is declared 'explicit'" op de volgende regels als hij de file vector (standaard library) meeneemt. De bewuste code regel is:
code:
1
    _Ty _Tmp = _Val;    // in case _Val is in sequence

Met als compiler output:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1>C:\Program Files\Microsoft Visual Studio 9.0\VC\include\vector(1211) : error C2558: class 'my_auto_ptr<T>' : no copy constructor available or copy constructor is declared 'explicit'
1>        with
1>        [
1>            T=CLine
1>        ]
1>        C:\Program Files\Microsoft Visual Studio 9.0\VC\include\vector(1153) : while compiling class template member function 'void std::vector<_Ty>::_Insert_n(std::_Vector_const_iterator<_Ty,_Alloc>,unsigned int,const _Ty &)'
1>        with
1>        [
1>            _Ty=LINEPTR,
1>            _Alloc=std::allocator<LINEPTR>
1>        ]
1>        c:\....\Provider.h(116) : see reference to class template instantiation 'std::vector<_Ty>' being compiled
1>        with
1>        [
1>            _Ty=LINEPTR
1>        ]
1>C:\Program Files\Microsoft Visual Studio 9.0\VC\include\vector(1235) : error C2558: class 'my_auto_ptr<T>' : no copy constructor available or copy constructor is declared 'explicit'
1>        with
1>        [
1>            T=CLine
1>        ]

Die LINEPTR komt uit de volgende definitie:
code:
1
typedef my_auto_ptr<CLine> LINEPTR;

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Sowieso 'mag' je geen auto_ptrs in standard containers stoppen.

"So the standards committee bent over backwards to do everything it could to help you out: The Standard auto_ptr was deliberately and specifically designed to break if you try to use it with the standard containers (or, at least, to break with most natural implementations of the standard library). To do this, the committee used a trick: auto_ptr's copy constructor and copy assignment operator take references to non-const to the right-hand-side object. The standard containers' single-element insert() functions take a reference to const, and hence won't work with auto_ptrs."

Klopt ook, want een auto_ptr cctor wijzigt het object dat van gekopieerd wordt. Ik vermoed -- het is niet mijn code -- dat als je typedeft naar std::tr1::shared_ptr het wel allemaal werkt. Of dus je my_auto_ptr afleiden van shared_ptr oid.

[ Voor 14% gewijzigd door Zoijar op 07-04-2011 10:44 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17:31

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoijar schreef op donderdag 07 april 2011 @ 10:36:
Ik vermoed -- het is niet mijn code -- dat als je typedeft naar std::tr1::shared_ptr het wel allemaal werkt. Of dus je my_auto_ptr afleiden van shared_ptr oid.
Exactly my point. Overigens noemde ik ook unique_ptr, die veel meer het gedrag van auto_ptr mimict, maar die bestaat natuurlijk pas in VS 2010 (omdat daar de r-value reference feature van C++0x voor nodig is), dus daar heb je niet zoveel aan.

[ Voor 6% gewijzigd door .oisyn op 07-04-2011 10:59 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Voor de originele behavior, ik denk dat je het beste op regel 15 een const_cast kan doen op lp. Dat is super-lelijk, inconsequent en evil, maar volgens mij is dat hetgene wat zou gebeuren in VC++6. De container zal dan waarschijnlijk de wrapper wel accepteren.

Disclaimer: container implementaties gaan er van uit dat sommige waarden constant zijn, veranderen kan dan ook rare behavior opleveren. Bijvoorbeeld als key-type in een gesorteerde container (std::set/map) gaat dit niet goed werken :)

[ Voor 43% gewijzigd door MLM op 07-04-2011 11:56 ]

-niks-


Verwijderd

Topicstarter
Zoijar schreef op donderdag 07 april 2011 @ 10:36:
Sowieso 'mag' je geen auto_ptrs in standard containers stoppen.

"So the standards committee bent over backwards to do everything it could to help you out: The Standard auto_ptr was deliberately and specifically designed to break if you try to use it with the standard containers (or, at least, to break with most natural implementations of the standard library). To do this, the committee used a trick: auto_ptr's copy constructor and copy assignment operator take references to non-const to the right-hand-side object. The standard containers' single-element insert() functions take a reference to const, and hence won't work with auto_ptrs."

Klopt ook, want een auto_ptr cctor wijzigt het object dat van gekopieerd wordt. Ik vermoed -- het is niet mijn code -- dat als je typedeft naar std::tr1::shared_ptr het wel allemaal werkt. Of dus je my_auto_ptr afleiden van shared_ptr oid.
Grinnik....
Tegen die quoto van de standards kan ik niet tegenop.

Ik ga even die shared_ptr uitproberen. Hij zou dus 'API compatible' moeten zijn.

In elk geval bedankt,

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Verwijderd schreef op donderdag 07 april 2011 @ 11:30:
[...]

Grinnik....
Tegen die quoto van de standards kan ik niet tegenop.

Ik ga even die shared_ptr uitproberen. Hij zou dus 'API compatible' moeten zijn.

In elk geval bedankt,
API compatible wel, maar het gedrag is nogal anders. Je hebt kans op bugs als de originele software uit gaat van het gedrag van auto_ptr.

-niks-


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Misschien dat je even moet testen op memory leaks, maar verder voorzie ik weinig bugs. Andersom wel, als je auto_ptrs in een container stopt, dan kunnen objecten plotseling verdwijnen met null-pointer bugs ten gevolg.
.oisyn schreef op donderdag 07 april 2011 @ 10:58:
(omdat daar de r-value reference feature van C++0x voor nodig is)
Interesting... moet me weer eens verdiepen in al het nieuwe spul. Ik hang nog steeds rond tr1 :)

[ Voor 39% gewijzigd door Zoijar op 07-04-2011 12:43 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
MLM schreef op donderdag 07 april 2011 @ 11:58:
[...]


API compatible wel, maar het gedrag is nogal anders. Je hebt kans op bugs als de originele software uit gaat van het gedrag van auto_ptr.
Je kunt in een wrapper (zoals hierboven) het originele gedrag redelijk dupliceren. Waar mogelijk reset je de originele pointer, behalve natuurlijk wanneer die const is.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

Topicstarter
MLM schreef op donderdag 07 april 2011 @ 11:27:
Voor de originele behavior, ik denk dat je het beste op regel 15 een const_cast kan doen op lp. Dat is super-lelijk, inconsequent en evil, maar volgens mij is dat hetgene wat zou gebeuren in VC++6. De container zal dan waarschijnlijk de wrapper wel accepteren.
Even ter info voor jou:
Ondanks dat ik de std::tr1::shared_ptr route aan het testen ben (alles is bouwbaar), heb ik heb ook even de const_cast suggestie geprobeerd. Helaas heeft dit geen effect (dezelfde eror), vanwege het weglaten van de const in regel 14.

[ Voor 17% gewijzigd door Verwijderd op 07-04-2011 17:48 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17:31

.oisyn

Moderator Devschuur®

Demotivational Speaker

Die moet je ook niet weghalen
C++:
1
2
    my_auto_ptr(const my_auto_ptr & lp) 
        :std::auto_ptr<T>(const_cast<my_auto_ptr&>(lp)){ }

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

.oisyn schreef op donderdag 07 april 2011 @ 18:03:
Die moet je ook niet weghalen
C++:
1
2
    my_auto_ptr(const my_auto_ptr & lp) 
        :std::auto_ptr<T>(const_cast<my_auto_ptr&>(lp)){ }
Dat bedoelde ik inderdaad. Maar het is wel evil, zoals ik zei, maar dat is >DENK IK< de originele behavior van die code. Waarom dit in VC6 compilede weet ik niet (gare compiler danwel gare STL)

-niks-


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

MLM schreef op donderdag 07 april 2011 @ 19:19:
Waarom dit in VC6 compilede weet ik niet (gare compiler danwel gare STL)
offtopic:
Beide :+ Als er ergens staat dat iets niet op een bepaalde manier gedaan mag worden, dan kan je ervan uitgaan dat VC6 het zo doet; er is geen grotere hel voor de C++ programmeur dan VC6

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17:31

.oisyn

Moderator Devschuur®

Demotivational Speaker

Jawel, VC5 :+

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Rutix
  • Registratie: Augustus 2009
  • Laatst online: 05-09-2024
Die is ook wel heel oud :P en iedereen weet dat VC onder 6.0 niet echt super was :D.
Zoijar schreef op donderdag 07 april 2011 @ 12:38:
[...]

Interesting... moet me weer eens verdiepen in al het nieuwe spul. Ik hang nog steeds rond tr1 :)
Ik weet niet of je Boost gebruikt maar als je dat wel doet dan is er niet veel nieuws ;). Veel van het nieuwe spul komt uit Boost ;)

Nothing to see here!


Verwijderd

Topicstarter
Daar was ik weer :)
Ik ben inmiddels duidelijk tot de conclusie gekomen dat mijn (roestige) C/C++ kennis mbt templates en smart pointer toepassingen ERNSTIG tekort schiet. Wel jammer.

Over die const_cast: ik was inderdaad vergeten dat we bij een eerdere poging die const hadden weggehaald. Mijn fout.

Uitgangspunt: de initiele code zoals bij start aangegeven, maar nu met de const_cast<> patch erin. Alle bovenstaande compiler errors lijken niet meer op te treden.

Het resultaat...
Zoals jullie vast al vermoedde vanwege die heerlijke oude VC++ compiler die 'alles maar accepteerd en 'foute dingen doet''... :X
... werd getrakteerd op een nieuwe error :|
En vandaar ook mijn opmerking hierboven. Ik heb vaak genoeg met operator overloading zitten werken, maar niet in deze context met templates en auto_ptr.

Als ik nog 1x (fingers crossed) van jullie kennis gebruik mag maken...

Probleem...
De VC9 compiler (VS2008) heeft nu blijkbaar een probleem met de operator=, welke dus niet is gedefinieerd in onze headerfile. Ik heb wat pogingen gedaan, maar dat leverde steeds casting issues op.
De compiler error:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
C:\Program Files\Microsoft Visual Studio 9.0\VC\include\xutility(3159) : error C2679: binary '=' : no operator found which takes a right-hand operand of type 'const LINEPTR' (or there is no acceptable conversion)
     c:\....\my_auto_ptr.h(23): could be 'my_auto_ptr<T> &my_auto_ptr<T>::operator =(my_auto_ptr<T> &) throw()'
     with
     [
         T=CLine
     ]
     while trying to match the argument list '(my_auto_ptr<T>, const LINEPTR)'
     with
     [
         T=CLine
     ]
     C:\Program Files\Microsoft Visual Studio 9.0\VC\include\xutility(3187) : see reference to function template instantiation 'void std::_Fill<my_auto_ptr<T>*,_Ty>(_FwdIt,_FwdIt,const _Ty &)' being compiled
     with
     [
         T=CLine,
         _Ty=LINEPTR,
         _FwdIt=my_auto_ptr<CLine> *
     ]
     C:\Program Files\Microsoft Visual Studio 9.0\VC\include\vector(1231) : see reference to function template instantiation 'void std::fill<my_auto_ptr<T>*,_Ty>(_FwdIt,_FwdIt,const _Ty &)' being compiled
     with
     [
         T=CLine,
         _Ty=LINEPTR,
         _FwdIt=my_auto_ptr<CLine> *
     ]
     C:\Program Files\Microsoft Visual Studio 9.0\VC\include\vector(1153) : while compiling class template member function 'void std::vector<_Ty>::_Insert_n(std::_Vector_const_iterator<_Ty,_Alloc>,unsigned int,const _Ty &)'
     with
     [
         _Ty=LINEPTR,
         _Alloc=std::allocator<LINEPTR>
     ]
     c:\....\Provider.h(116) : see reference to class template instantiation 'std::vector<_Ty>' being compiled
     with
     [
         _Ty=LINEPTR
     ]


Hebben jullie wederom een ingeving?
Alvast bedankt van iemand met een 'vastgeroeste' knikker...

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17:31

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zelfde verhaal als met de copy ctor. Gewoon een operator= definieren die een const my_auto_ptr& verwacht, en deze const-casten en doorspelen aan auto_ptr::operator=()

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Maar snap je ook waarom het fout gaat? Dat is wel handig om te weten namelijk. Een auto_ptr neemt ownership over bij een kopie. Er is -- als het goed is -- dus altijd maar exact 1 auto_ptr die ownership over het object heeft en dus ook verantwoordelijk is voor het wissen daarvan. Als je een kopie, B, maakt van auto_ptr A, dan krijgt B dus ownership en is A daarna "leeg". Vergelijk dit met A op nul zetten. Een copy constructor of een assignment operator _veranderen_ dus het source object door die op nul te zetten. Daarom zijn die methodes niet 'const'.

Echter, de meeste routines verwachten dat een kopie wel 'const' is en niet de source verandert -- zo ook alle standaard containers. Die zoeken dus een assignment operator die een const object accepteert als argument. Maar de auto_ptr heeft zo'n methode niet vanwege bovenstaande. Resultaat is jouw error.

const_cast-en is daarom ook erg riskant: je methode zegt namelijk "ik zal het object niet veranderen, nee doe ik niet, nee, echt niet, geloof me maar" ... en dan toch doen.

[ Voor 9% gewijzigd door Zoijar op 08-04-2011 17:51 ]

Pagina: 1