Frage

Ich habe eine C ++ Datenstruktur erhält, die ein erforderliches „Scratchpad“ für andere Berechnungen ist. Es ist nicht lange gelebt, und es ist nicht häufig so nicht die Leistung entscheidend verwendet. Es enthält jedoch einen Zufallszahlengenerator unter anderem aktualisierbar Tracking-Felder, und während der Ist-Wert des Generators ist nicht wichtig, es is wichtig, dass der Wert aktualisiert wird und nicht kopiert und weiterverwendet. Das bedeutet, dass in der Regel Objekte dieser Klasse wird als Referenz übergeben.

Wenn eine Instanz nur einmal erforderlich ist, der natürlichste Ansatz ist es, sie zu konstruieren, wo auch immer benötigt (vielleicht eine Factory-Methode oder einen Konstruktor) und gab dann die Scratchpad zur aufwändigen Methode. Verbraucher Methode Signaturen über einen Verweis verwenden, da sie nicht wissen, ist dies die einzige Anwendung, aber Fabrik Methoden und Konstruktoren zurückkehren nach Wert -. Und man kann nicht unbenannte Provisorien durch Verweis übergeben

Gibt es eine Möglichkeit, den Code mit fiesen temporären Variablen Verstopfung zu vermeiden? Ich mag Dinge wie die folgenden vermeiden:

scratchpad_t<typeX<typeY,potentially::messy>, typename T> useless_temp = factory(rng_parm);
xyz.initialize_computation(useless_temp);

Ich konnte das Scratchpad macht eigen mutable und einfach alle Parameter const & beschriften, aber das macht mich nicht als Best-Practice-schlagen, da es irreführend, und ich kann das nicht für die Klassen I-Regelung nicht in vollem Umfang. Vorbei rvalue Referenz erfordern würde Überlastungen für alle Verbraucher von Scratchpad-Zugabe, welche Art von Niederlagen der Zweck -. Mit klaren und präzisen Code

In Anbetracht der Tatsache, dass die Leistung nicht kritisch ist (aber die Codegröße und Lesbarkeit sind), Was ist der Best-Practice-Ansatz in einem solchen Scratchpad zu vorbei? Verwendung von C ++ 0x Features ist in Ordnung, wenn < em> erforderlich aber vorzugsweise C ++ 03-only-Funktionen ausreichen sollten.

Edit: Um klar zu sein, eine vorübergehende Verwendung ist machbar, es ist nur schade Unordnung in Code, den ich zu vermeiden möchten. Wenn Sie noch nie den temporären einen Namen geben, ist es eindeutig nur einmal verwendet, und die weniger Codezeilen zu lesen, desto besser. Auch in der Konstrukteurs initializers, es ist unmöglich, Provisorien zu erklären.

War es hilfreich?

Lösung

Während es nicht in Ordnung ist rvalues ??an Funktionen übergeben nicht konstante Referenzen zu akzeptieren, ist es in Ordnung Mitgliederfunktionen auf rvalues ??zu nennen, aber die Member-Funktion nicht weiß, wie es hieß. Wenn Sie einen Verweis auf das aktuelle Objekt zurückkehren, können Sie rvalues ??zu lvalues ??konvertieren:

class scratchpad_t
{
    // ...

public:

    scratchpad_t& self()
    {
        return *this;
    }
};

void foo(scratchpad_t& r)
{
}

int main()
{
    foo(scratchpad_t().self());
}

Beachten Sie, wie der Aufruf von self() ergibt einen L-Wert-Ausdruck, obwohl scratchpad_t ein R-Wert ist.

Sie mir bitte korrigieren, wenn ich falsch bin, aber Rvalue Referenzparameter nicht akzeptieren lvalue Referenzen so mit ihnen erfordern würde Überlastungen für alle Verbraucher von Scratchpad-Zugabe, die auch unglücklich ist.

Nun können Sie Vorlagen verwenden ...

template <typename Scratch> void foo(Scratch&& scratchpad)
{
    // ...
}

Wenn Sie foo mit einem R-Wert Parameter aufrufen, wird Scratch zu scratchpad_t abgeleitet werden, und somit wird Scratch&& scratchpad_t&& sein.

Und wenn Sie foo mit einem L-Wert-Parameter aufrufen, wird Scratch zu scratchpad_t& abgeleitet werden, und wegen der Referenz Kollabieren Regeln Scratch&& auch scratchpad_t& sein.

Beachten Sie, dass die formale Parameter scratchpad einen Name ist und somit ein L-Wert, unabhängig davon, ob diese Art ist eine L-Wert Kennnummer oder eine rvalue Referenz. Wenn Sie scratchpad an andere Funktionen übergeben möchten, müssen Sie nicht die Vorlage Trick für diese Funktionen benötigen mehr, nur ein L-Wert-Referenzparameter verwendet werden.

By the way, tun Sie erkennen, dass die temporäre Scratchpad in xyz.initialize_computation(scratchpad_t(1, 2, 3)); beteiligt werden so schnell zerstört werden, wie initialize_computation getan wird, nicht wahr? Das Speichern der Referenz innerhalb des xyz Objekt für spätere Nutzer würde eine extrem schlechte Idee.

self() kein Mitglied Verfahren sein muss, kann es eine Templat-Funktion sein

Ja, das ist auch möglich, obwohl ich es umbenennen würde die Absicht deutlicher zu machen:

template <typename T>
T& as_lvalue(T&& x)
{
    return x;
}

Andere Tipps

Ist das Problem nur, dass diese:

scratchpad_t<typeX<typeY,potentially::messy>, typename T> useless_temp = factory(rng_parm);

ist hässlich? Wenn ja, dann warum es nicht das ändern:

auto useless_temp = factory(rng_parm);

Ich persönlich würde lieber sehen const_cast als mutable. Als ich mutable sehen, ich gehe davon aus jemandes logische const-ness zu tun, und denken nicht viel davon. const_cast jedoch wirft rote Fahnen, als Code wie dieser sollte.

Eine Option wäre so etwas wie shared_ptr zu verwenden (auto_ptr funktionieren würde auch je nachdem, was factory tat) und übergibt es von Wert, der die Kosten für eine Kopie vermeidet und hält nur eine einzige Instanz, kann aber in Ihrer Fabrik übergeben werden Verfahren.

Wenn Sie das Objekt im Heap zuweisen könnten Sie in der Lage sein, den Code etwas zu konvertieren, wie:

std::auto_ptr<scratch_t> create_scratch();

foo( *create_scratch() );

Die Fabrik erzeugt und gibt eine auto_ptr statt ein Objekt in dem Stapel. Die zurück auto_ptr vorübergehend wird das Eigentum an dem Objekt, aber Sie dürfen nicht konstante Methoden auf Zeit anrufen und Sie können die Zeigerdereferenzierung eine echte Referenz zu erhalten. An der nächsten Sequenz Punkt wird der Smart Pointer zerstört werden und der Speicher freigegeben. Wenn Sie die gleiche scratch_t auf verschiedene Funktionen in einer Reihe weitergeben möchten, können Sie einfach den intelligenten Zeiger erfassen:

std::auto_ptr<scratch_t> s( create_scratch() );
foo( *s );
bar( *s );

Dies kann mit std::unique_ptr in der kommenden Norm ersetzt werden.

I markiert FredOverflow Antwort als Antwort auf seinen Vorschlag, ein Verfahren zu verwenden, einfach eine nicht konstante Referenz zurückzukehren; Dies funktioniert in C ++ 03. Diese Lösung erfordert ein Mitglied Verfahren pro Scratchpad artigen Typ, aber in C ++ 0x können wir schreiben auch diese Methode generell für jede Art:

template <typename T> T & temp(T && temporary_value) {return temporary_value;}

Diese Funktion einfach nach vorne normale lvalue Referenzen und wandelt rvalue Referenzen in lvalue Referenzen. Natürlich tun dies kehrt einen änderbaren Wert, deren Ergebnis ignoriert wird -. Was genau passiert zu sein, was ich will, kann aber in manchen Kontexten seltsam erscheinen,

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top