2010-02-28 8 views
7

Ich sah gerade this nice Copy-on-Write-Zeiger Implementierung. Es sieht ziemlich generisch und nützlich aus, meine Frage ist also: Ist eine solche Klasse in einem der C++ - Toolkits (Boost, Loki usw.) enthalten? Wenn nicht, würde ich gerne wissen, warum, weil es ein wirklich nützliches Idiom ist und anscheinend eine generische Implementierung machbar ist (wie die, mit der ich verlinkt bin).Warum gibt es keinen boost :: copy_on_write_ptr?

+3

Es ist im Qt-Toolkit enthalten und heißt 'QSharedDataPointer'. Es ist ganz nett. –

Antwort

6

Es gab viele Diskussionen über die Möglichkeit, und mindestens eine vorgeschlagene Version von was schließlich als auto_ptr herauskam, war für einen COW-Referenzzeiger.

Leider ist die Zeit für COW größtenteils verstrichen. Wenn Sie einen COW-Zeiger (oder COW-was auch immer) thread-safe machen, können Sie ernsthafte performance problems einführen.

Bearbeiten: Rerading, ich fühle mich verpflichtet, darauf hinzuweisen, dass nicht alle Verwendung von COW unbedingt veraltet. Es gibt Zeiten, in denen es immer noch Sinn macht. Der Overhead eines Thread-sicheren Inkrements ist ziemlich fest - es ist also nur eine Frage, wie groß ein Objekt sein muss oder wie teuer es ist, es zu kopieren, damit COW Sinn macht. Es gibt auch Zeiten/Orte, an denen Sie Lose Kopien eines (unveränderten) Objekts haben, und die Einsparungen im Speicher können ein angemessener Kompromiss sein - die Einsparungen im Speicher rechtfertigen einige zusätzliche Prozessorzeit. Wenn Sie Paging wenig Daten auf/von der Festplatte speichern können, können Sie in Eile voraus kommen.

+0

Das macht mich traurig. :( – Frank

+0

@Frank: Traurig? Wie so? Es führt einfach nicht zu schneller Code, also warum es verwenden? – jalf

2

Wie Jerry Coffin sagte, es wurde gezeigt, dass das COW-Idiom Performance-Probleme eingeführt ... aber es gibt tatsächlich ein anderes Problem.

Es ist nicht möglich (wie in dem Artikel, auf den Sie verweisen), eine generische Implementierung von COW zu schreiben. In der COW-Implementierung von std::string wird die Kopie immer dann ausgeführt, wenn eine Operation aufgerufen wird, die den Zustand der Zeichenfolge tatsächlich ändert. Wie aber soll ein Zeiger das wissen? Es hat kein Wissen über die Klasse, auf die es hinweist.

Zum Beispiel nehmen wir an, ich dies tun:

void method(Foo& foo, flag_t flag) 
{ 
    if (flag == flag::Yes) foo.modify(); 
} 

void invoke(COWPointer<Foo> ptr) 
{ 
    method(*ptr, flag::No); 
} 

Oups! Ich mache eine Kopie des Foo Objekts, obwohl es nicht modifiziert wird!

Das Problem ist, dass während dieser KUH-Klasse hilft, Sie tatsächlich zu wickeln hat:

class Foo 
{ 
public: 

private: 
    COWPointer<FooImpl> mImpl; 
}; 

Und dann Methoden der Foo, die wirklich das Objekt zum Kopieren des FooImpl Zustand verantwortlich sein wird, modifiziert. So sicher, dass die Klasse hilft, aber es ist auch keine Wunderwaffe.

Und das alles Ärger ... ohne wegen der Probleme bei der Synchronisierung der tatsächlich gewinnt Leistung in einer MT-Anwendung sicher zu sein ...

Ist es nicht einfacher, um tatsächlich das Kopieren, wann immer möglich zu vermeiden (Referenzen/Zeiger verwendet werden) anstatt Ihre Klasse für eine mögliche Verstärkung in einigen Situationen, die Benutzer bestrafen, die bereits auf Performances Probleme kümmerte optimieren?

0

Es gibt einen Widerspruch zwischen "Zeiger" und "Kopie beim Schreiben": Per Definition ändert die Dereferenzierung eines Zeigers es nicht, und die Änderung *p ändert sich nicht p.

So kann ein Const-Zeiger dereferenziert werden, und der resultierende Lvalue kann geändert werden.

Sie sprechen wirklich von einem Ein-Element-Container, nicht von einem Zeiger.