temporäre instanz bei default argument vermeiden



  • ich möchte gern folgendes machen:

    void foo(boost::any const & arg = 0) { ... }
    

    ich gehe davon aus, dass dieser code für jeden "leeren" aufruf eine temporäre instanz von boost::any erzeugt.

    also hab ich es geändert:

    static boost::any const none;
    void foo(boost::any const & arg = none) { ... }
    

    so muss doch keine temporäre instanz mehr erzeugt werden?
    was wäre in folgendem fall:

    static boost::any const none;
    void foo(boost::any const & arg = none) { ... }
    
    // andere compileunit
    class my_class {
    public:
        my_class() { foo(); } // ruft foo ohne argument auf    
    };
    
    my_class my_object; // globale instanz von my_class
    

    sehe ich das richtig, dass dieser code undefiniertes verhalten erzeugt, weil foo aufgerufen wird, bevor none sicher erzeugt wurde?


  • Mod

    suma dartson schrieb:

    sehe ich das richtig, dass dieser code undefiniertes verhalten erzeugt, weil foo aufgerufen wird, bevor none sicher erzeugt wurde?

    Das hängt davon ab, was foo mit dem Argument anstellt. Ein lvalue kann an eine Referenz gebunden werden, sofern es auf entsprechend reservierten Speicher verweist - es ist nicht zwingend erforderlich, dass das Objekt bereits oder noch lebt.



  • Würde sich bei deinem Beispiel nicht Überladung anbieten?

    void foo();
    void foo(boost::any const& arg);
    

    Damit wird bestimmt keine unnötige Kopie erzeugt oder undefiniertes Verhalten ausgelöst. Ausserdem entfällt eine Abfrage wie if (arg == none), du ja weisst, ob ein Argument übergeben wurde.

    Gruß
    Don06



  • camper schrieb:

    Das hängt davon ab, was foo mit dem Argument anstellt.

    mindestens mal

    if(!arg.empty())
    {
       ...
    }
    

    Don06 schrieb:

    Würde sich bei deinem Beispiel nicht Überladung anbieten?

    wenn es nur um die eine stelle ginge, ja. aber es geht um ein interface, wo foo öfter mal überschrieben wird, da möchte ich das lieber mit einer funktion und default-argument machen.


  • Mod

    suma dartson schrieb:

    camper schrieb:

    Das hängt davon ab, was foo mit dem Argument anstellt.

    mindestens mal

    if(!arg.empty())
    {
       ...
    }
    

    könnte auch

    if(&arg!=&none&&!arg.empty())
    {
       ...
    }
    

    sein, dann besteht kein Problem (nicht, dass ich das für eine gute Lösung halte).



  • Mach es so:

    void foo(boost::any const & arg = boost::any()) { ... }
    

    Dann wird zwar auch immer ein temporäres Objekt erzeugt, allerdings ist ein "leeres any" sehr billig zu erzeugen & löschen.
    Ein "any" mit einem Integer drin kostet dagegen u.U. wesentlich mehr.

    Ich weiss nicht ob die aktuelle Boost Version eine Art "small object optimization" bei any verwendet. Wenn das so wäre wäre ein "any" mit einem Integer drinnen vermutlich auch nicht SEHR teuer. Wenn es keine Optimierung gibt ist der Unterschied allerdings sicher dramatisch.



  • hustbaer schrieb:

    Mach es so:

    void foo(boost::any const & arg = boost::any()) { ... }
    

    ok, das scheint mir ein guter kompromiss zu sein. ein leeres any kostet wirklich nicht viel.


Anmelden zum Antworten