Index: mojo/public/cpp/bindings/lib/shared_data.h |
diff --git a/mojo/public/cpp/bindings/lib/shared_data.h b/mojo/public/cpp/bindings/lib/shared_data.h |
index e2de974e7cf688e4bb9b69ad8b707c4cde823be5..6803a5c80218f999f98293480efbd0dd19b8a438 100644 |
--- a/mojo/public/cpp/bindings/lib/shared_data.h |
+++ b/mojo/public/cpp/bindings/lib/shared_data.h |
@@ -14,41 +14,66 @@ namespace mojo { |
namespace internal { |
// Used to allocate an instance of T that can be shared via reference counting. |
+// |
+// A default constructed SharedData does not have a Holder until it is set, |
+// either by assignment, or by accessing the value. As a result, it is not tied |
+// to any thread. The Holder is lazily allocated on first access. The complexity |
+// is due to the behaviour around copying. If a default constructed SharedData |
+// is copied into another, the two share the same empty state, and changing the |
+// value of one will affect the other. |
template <typename T> |
class SharedData { |
public: |
- ~SharedData() { holder_->Release(); } |
+ ~SharedData() { |
+ if (holder_) |
+ holder_->Release(); |
+ } |
- SharedData() : holder_(new Holder()) {} |
+ SharedData() : holder_(nullptr) {} |
explicit SharedData(const T& value) : holder_(new Holder(value)) {} |
- SharedData(const SharedData<T>& other) : holder_(other.holder_) { |
+ SharedData(const SharedData<T>& other) { |
+ other.LazyInit(); |
+ holder_ = other.holder_; |
holder_->Retain(); |
} |
SharedData<T>& operator=(const SharedData<T>& other) { |
+ other.LazyInit(); |
if (other.holder_ == holder_) |
return *this; |
- holder_->Release(); |
+ if (holder_) |
+ holder_->Release(); |
holder_ = other.holder_; |
holder_->Retain(); |
return *this; |
} |
void reset() { |
- holder_->Release(); |
- holder_ = new Holder(); |
+ if (holder_) |
+ holder_->Release(); |
+ holder_ = nullptr; |
} |
void reset(const T& value) { |
- holder_->Release(); |
+ if (holder_) |
+ holder_->Release(); |
holder_ = new Holder(value); |
} |
- void set_value(const T& value) { holder_->value = value; } |
- T* mutable_value() { return &holder_->value; } |
- const T& value() const { return holder_->value; } |
+ void set_value(const T& value) { |
+ LazyInit(); |
+ holder_->value = value; |
+ } |
+ T* mutable_value() { |
+ LazyInit(); |
+ return &holder_->value; |
+ } |
+ const T& value() const { |
+ LazyInit(); |
+ return holder_->value; |
+ } |
private: |
class Holder { |
@@ -74,7 +99,12 @@ class SharedData { |
MOJO_DISALLOW_COPY_AND_ASSIGN(Holder); |
}; |
- Holder* holder_; |
+ void LazyInit() const { |
+ if (!holder_) |
+ holder_ = new Holder(); |
+ } |
+ |
+ mutable Holder* holder_; |
}; |
} // namespace internal |