禁止基类的复制构造

时间:2014-09-24 08:48:19

标签: c++11 copy-constructor smart-pointers base-class

我想快速实现一些人称之为"所有者指针",即确保独特所有权语义的智能指针,同时提供"观察者"指针不能保持对象存活,但可以测试它是否存在。

我尝试这样做最直接的方法是继承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 ...

导入所有内容

1 个答案:

答案 0 :(得分:1)

我不认为继承std::shared_ptr是可行的方法。如果你真的想要做得恰到好处,我认为你应该自己实现它,包括所有引用计数。实现智能指针实际上 很难。

但是,在大多数情况下,如果您只是想要满足您需求的东西,请使用构图。

我很想知道你想要做什么,我不相信这是一个好主意,但我已经开始使用组合实现OwnerPointerObserverPointer对:< / 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();
}

Live demo.

它可能需要一些工作,它不能提供std :: shared_ptr&amp;的完整功能集。 std :: weak_ptr但在大多数情况下它不需要,只需创建你需要的东西。

我已经延伸了&#34;独特所有权的定义&#34;通过提供RAII ObserverLock对象,该对象只能用于保持ObserverPointer活着。从技术上讲,它拥有&#34;指针,但它的功能非常有限,你不能创建多个&#34; OwnerPointer&#34;。