Toon posts:

[c++] Flexibeler objecten constructen in STL containers

Pagina: 1
Acties:

Verwijderd

Topicstarter
Nieuwe objecten in STL containers kun je meestal laten copy-constructen van een gegeven 'source' object, bijvoorbeeld:
code:
1
2
void std::vector<T>::push_back (T const & r);
// het nieuwe object wordt ge-copy-construct met r
Het is (met de huidige std::vector interface) niet mogelijk om nieuwe objecten direct door een constructor naar keuze (met willekeurige parameter-combinaties) te laten constructen. Deze inflexibiliteit zorgt ervoor dat er vaak (conceptueel overbodige) temporaries nodig zijn:
code:
1
2
3
4
5
6
7
struct S { S (int, int) {} };

void f ()
{
  std::vector<S> v;
  v.push_back(S(0,0)); // helaas per sé een temporary nodig
}
Er wordt hier een object aangemaakt dat nadat het gekopieerd is meteen weer weggegooid wordt. Ik vind dit lelijk, en volgens mij kan het beter.

Door de volgende functies aan std::vector toe te voegen:
code:
1
2
3
4
5
6
7
8
9
10
template <typename A>
void direct_push_back (A a);

template <typename A, typename B>
void direct_push_back (A a, B b);

template <typename A, typename B, typename C>
void direct_push_back (A a, B b, C c);

etc.
en deze functies de parameters te laten doorgeven aan de constructor van het nieuwe object, kan de gebruiker het object direct 'op locatie' (in de controlled sequence) laten constructen door een constructor naar keuze:
code:
1
2
3
4
5
void g ()
{
  std::vector<S> v;
  v.direct_push_back(0, 0); // geen temporary nodig
}
Ziet er goed uit, nietwaar? ;)

Mijn onvermijdelijke vragen zijn dan ook: Waarom zit dit niet in de STL? Wat is hier mis mee? Wat zie ik over het hoofd? (Ik heb deze constructie reeds uitgeprobeerd met de met mijn compiler meegeleverde STL, en het werkt prima.)

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Ik denk dat ze het niet echt nodig vonden. Er zijn heel veel dingen te bedenken die "wel handig" zijn. (zie loki en boost hehe ;) ) En dat het schrijven van x template functies om 1 temporary te vermijden niet echt hoge prioriteit was. En wie weet optimized je compiler dit er wel uit, weet ik niet zeker. "Standard writers have deadlines too" ;)
Het is wel een leuk idee, hoewel ik het niet echt heel duidelijk leesbaar vind. Maar inherit van vector en voeg die functie toe als je het nodig hebt :)

Verwijderd

Ik denk dat de STL en C++ in het algemeen nooit bedoeld zijn geweest om een zo hoog mogelijke performance te geven (en daar gaat het jou toch om neem ik aan, dat je klaagt over een 'overbodige' temporary), maar om het de ontwikkelaar zo gemakkelijk mogelijk te maken... Vandaar dat het geen prioriteit gehad zal hebben deze temporary te vermijden...

Verwijderd

Topicstarter
Zoijar schreef op 01 september 2002 @ 13:12:
Ik denk dat ze het niet echt nodig vonden. Er zijn heel veel dingen te bedenken die "wel handig" zijn. (zie loki en boost hehe ;) ) En dat het schrijven van x template functies om 1 temporary te vermijden niet echt hoge prioriteit was. En wie weet optimized je compiler dit er wel uit, weet ik niet zeker.
Hmm, lijkt me vrijwel onmogelijk. Dat zou namelijk betekenen dat de constructor aanroep in f al meteen het object in de controlled sequence zou constructen, en volgens mij gaat dat toch iets te ver.. (niet alleen in complexiteit, maar ook in wat de standaard toelaat).
Het is wel een leuk idee, hoewel ik het niet echt heel duidelijk leesbaar vind. Maar inherit van vector en voeg die functie toe als je het nodig hebt :)
Hier zit 'em het probleem: de public interface volstaat niet voor het implementeren van deze functies ;( (een protected interface is er verder niet).

Verwijderd

Topicstarter
Verwijderd schreef op 01 september 2002 @ 13:49:
Ik denk dat de STL en C++ in het algemeen nooit bedoeld zijn geweest om een zo hoog mogelijke performance te geven (en daar gaat het jou toch om neem ik aan, dat je klaagt over een 'overbodige' temporary), maar om het de ontwikkelaar zo gemakkelijk mogelijk te maken... Vandaar dat het geen prioriteit gehad zal hebben deze temporary te vermijden...
De STL en C++ in het algemeen zijn absoluut wel bedoeld om een zo hoog mogelijke performance te geven :). De STL is nou juist een mooi voorbeeld van een library die retesnel geimplementeerd kan worden (ik doel uiteraard niet op de ontwikkeltijd..), en tegelijk gebruikersvriendelijk is. Voor meer informatie over de doelstellingen en filosofiëen achter C++ verwijs ik je naar Stroustrup's 'The Design and Evolution of C++'.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Je idee is al eerder geopperd (dat is dus goed).
Een probleem is dat je in ruil voor het niet kopieren van het contained object alle parameters (A,B,C enzo ) wel kopieert - je gebruikt pass-by-value. Pass-by-reference zou sneller zijn, maar dat werkt niet altijd.

De STL containers zijn ontwikkeld om "values" op te slaan, objecten die "goedkoop" gekopieerd kunnen worden. Met behulp van dit soort containers en smart pointers (zie Boost of Loki ) kun je relatief eenvoudig ook containers bouwen als het kopieren van de objecten zelf te duur wordt. Vanwege de STL opzet is dit een optimalisatie die je kunt uitstellen tot profiling aantoont dat het nodig 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
MSalters schreef op 02 september 2002 @ 00:11:
Je idee is al eerder geopperd (dat is dus goed).
Een probleem is dat je in ruil voor het niet kopieren van het contained object alle parameters (A,B,C enzo ) wel kopieert - je gebruikt pass-by-value. Pass-by-reference zou sneller zijn, maar dat werkt niet altijd.
Hier had ik ook al aan gedacht, en een effectieve workaround is het gebruik van reference wrappers (zoals bijvoorbeeld die van Boost).
De STL containers zijn ontwikkeld om "values" op te slaan, objecten die "goedkoop" gekopieerd kunnen worden. Met behulp van dit soort containers en smart pointers (zie Boost of Loki ) kun je relatief eenvoudig ook containers bouwen als het kopieren van de objecten zelf te duur wordt. Vanwege de STL opzet is dit een optimalisatie die je kunt uitstellen tot profiling aantoont dat het nodig is.
Het feit dat std::auto_ptr niet in STL containers gebruikt kan worden door de CopyConstructible en (const) Assignable requirements die deze containers voor hun element typen vereisen is ironisch genoeg juist de aanleiding van dit topic. De in de startpost beschreven functies zorgen ervoor dat voor element insertion deze requirements niet meer nodig zijn. Ik ben momenteel aan het experimenteren met containers die deze requirements helemaal niet meer nodig hebben, en zo zonder problemen std::auto_ptr's kunnen bevatten.

Ik weet dat boost::shared_ptr gebruikt kan worden in STL containers, maar ik vind het achterlijk om voor ieder object een reference count bij te houden terwijl ik van tevoren weet dat ik de shared_ptr niet ga kopieren...

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Verwijderd schreef op 02 september 2002 @ 00:52:
Het feit dat std::auto_ptr niet in STL containers gebruikt kan worden door de CopyConstructible en (const) Assignable requirements die deze containers voor hun element typen vereisen is ironisch genoeg juist de aanleiding van dit topic. De in de startpost beschreven functies zorgen ervoor dat voor element insertion deze requirements niet meer nodig zijn. Ik ben momenteel aan het experimenteren met containers die deze requirements helemaal niet meer nodig hebben, en zo zonder problemen std::auto_ptr's kunnen bevatten.

Ik weet dat boost::shared_ptr gebruikt kan worden in STL containers, maar ik vind het achterlijk om voor ieder object een reference count bij te houden terwijl ik van tevoren weet dat ik de shared_ptr niet ga kopieren...
Succes met het schrijven van je iterators, in dat geval. Ik zou nl. niet weten hoe je van zo'n container een back_insert_iterator krijgt, of hoe je die zou moeten gebruiken.

De beperkingen lijken dan wel onredelijk, maar objecten die niet/slecht te kopieren zijn, dat zijn meestal "grote" objecten - een grote sizeof(), een groot heap gebruik, of I/O gerelateerd. Dan is de overhead van een smart pointer relatief klein, zeker als je een intrusive counter kunt gebruiken (dwz counter in een base class van het gemanagde object).

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


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Nog even een quick note: std::sort werkt natuurlijk niet als je geen pivot element kunt maken - en een pivot element is een kopie van een element uit je container.

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
Ik ben me er volledig van bewust dat allerlei dingen (zoals een back insert iterator) niet meer mogelijk zijn wanneer elementen niet meer gekopieerd kunnen worden, maar toch vind ik het de moeite waard om dit eens te proberen. Als in een bepaalde situatie die features namelijk toch al niet nodig zijn, zou zo'n container imho een uitermate geschikte (en veel schonere) oplossing bieden.

Het gaat me overigens niet zozeer om de overhead van een reference counter (intrusive of non-intrusive), het gebruik van reference counting wanneer er maar 1 reference gaat zijn vind ik gewoon lelijk.. :|
Pagina: 1