我想快速实现一些人称之为"所有者指针",即确保独特所有权语义的智能指针,同时提供"观察者"指针不能保持对象存活,但可以测试它是否存在。
我尝试这样做最直接的方法是继承std::shared_ptr
,并禁用其复制构造,以便其他指针不能实际共享该对象。
这就是我现在所拥有的:
#include <memory>
#include <iostream>
template <class T>
struct owner_ptr : public std::shared_ptr<T> {
// Import constructors
using std::shared_ptr<T>::shared_ptr;
// Disable copy-construction
owner_ptr(owner_ptr<T> const&) = delete;
// Failed attempt at forbidding what comes next
operator std::shared_ptr<T> const&() = delete;
};
struct Foo {
Foo() {
std::cout << "Hello Foo\n";
}
~Foo() {
std::cout << "G'bye Foo\n";
}
void talk() {
std::cout << "I'm talkin'\n";
}
};
owner_ptr<Foo> fooPtr(new Foo);
int main(int, char**) {
// This should not compile, but it does.
std::shared_ptr<Foo> sptr = fooPtr;
// Simple tests
fooPtr->talk();
(*fooPtr).talk();
// Confirmation that two pointers are sharing the object (it prints "2").
std::cout << sptr.use_count() << '\n';
}
我一直在拉这个头发。如何从std::shared_ptr
禁止owner_ptr
的复制构建?我不喜欢私下继承,然后从std::shared_ptr
...
答案 0 :(得分:1)
我不认为继承std::shared_ptr
是可行的方法。如果你真的想要做得恰到好处,我认为你应该自己实现它,包括所有引用计数。实现智能指针实际上 很难。
但是,在大多数情况下,如果您只是想要满足您需求的东西,请使用构图。
我很想知道你想要做什么,我不相信这是一个好主意,但我已经开始使用组合实现OwnerPointer
和ObserverPointer
对:< / p>
#include <memory>
#include <iostream>
struct Foo {
Foo() {std::cout << "Hello Foo\n"; }
~Foo() { std::cout << "G'bye Foo\n"; }
void talk() { std::cout << "I'm talkin'\n"; }
};
template <class T>
class ObserverPointer; // Forward declaration.
template<class T>
class OwnerPointer; // Forward declaration.
// RAII object that can be obtained from ObserverPointer
// that ensures the ObserverPointer does not expire.
// Only operation is to test validity.
template <class T>
class ObserverLock {
friend ObserverPointer<T>;
private:
std::shared_ptr<T> impl_;
ObserverLock(const std::weak_ptr<T>& in) : impl_(in.lock()) {}
public:
// Movable.
ObserverLock(ObserverLock&&) = default;
ObserverLock& operator=(ObserverLock&&) = default;
// Not copyable.
ObserverLock& operator=(const ObserverLock&) = delete;
ObserverLock(const ObserverLock&) = delete;
// Test validity.
explicit operator bool() const noexcept { return impl_ != nullptr;}
};
template <class T>
class ObserverPointer {
private:
std::weak_ptr<T> impl_;
T* raw_;
public:
ObserverPointer(const OwnerPointer<T>& own) noexcept : impl_(own.impl_), raw_(own.get()) {}
T* get() const { return raw_; }
T* operator->() const { return raw_; }
T& operator*() const { return *raw_; }
ObserverPointer() : impl_(), raw_(nullptr) { }
ObserverPointer(const ObserverPointer& in) = default;
ObserverPointer(ObserverPointer&& in) = default;
ObserverPointer& operator=(const ObserverPointer& in) = default;
ObserverPointer& operator=(ObserverPointer&& in) = default;
bool expired() { return impl_.expired(); }
ObserverLock<T> lock() { return ObserverLock<T>(impl_); }
};
template <class T>
struct OwnerPointer {
friend ObserverPointer<T>;
private:
std::shared_ptr<T> impl_;
public:
// Constructors
explicit OwnerPointer(T* in) : impl_(in) {}
template<class Deleter>
OwnerPointer(std::unique_ptr<T, Deleter>&& in) : impl_(std::move(in)) { }
OwnerPointer(std::shared_ptr<T>&& in) noexcept : impl_(std::move(in)) { }
OwnerPointer(OwnerPointer<T>&&) noexcept = default;
OwnerPointer(OwnerPointer<T> const&) = delete;
// Assignment operators
OwnerPointer& operator=(OwnerPointer<T> const&) = delete;
OwnerPointer& operator=(OwnerPointer<T>&&) = default;
T* get() const { return impl_.get(); }
T* operator->() const { return impl_.get(); }
T& operator*() const { return *impl_; }
explicit operator ObserverPointer<T>() const noexcept { return ObserverPointer<T>(impl_);}
explicit operator bool() const noexcept { return impl_;}
};
// Convenience function equivalent to make_shared
template <class T, class... Args>
OwnerPointer<T> make_owner(Args && ...args) {
return OwnerPointer<T>(new T(std::forward<Args>(args)...));
}
int main() {
auto owner = make_owner<Foo>();
ObserverPointer<Foo> observer = owner;
auto lock = observer.lock();
if (lock)
observer->talk();
}
它可能需要一些工作,它不能提供std :: shared_ptr&amp;的完整功能集。 std :: weak_ptr但在大多数情况下它不需要,只需创建你需要的东西。
我已经延伸了&#34;独特所有权的定义&#34;通过提供RAII ObserverLock
对象,该对象只能用于保持ObserverPointer
活着。从技术上讲,它拥有&#34;指针,但它的功能非常有限,你不能创建多个&#34; OwnerPointer&#34;。