繁体   English   中英

作用域std :: unique_ptr投

[英]Scoped std::unique_ptr cast

我目前正在使用智能指针来编写一些代码,在这些代码中,有必要在许多点上将这些指针转换为它们的基本类型,并将它们作为const参数传递给函数。 目前,我正在使用shared_ptr和标准的指针转换函数来实现此目的,但这似乎效率低下(因为每个转换至少要花费一个CAS)并且还会产生误导性(因为我们没有对共享关系进行建模,因此父级是该项的唯一所有者)物体)。

因此,我想出了以下方法,但想检查一下它是否确实安全,或者是否有一些边缘情况会破坏它?

template <typename ToType, typename FromType>
class FTScopedCastWrapper {
public:
    explicit FTScopedCastWrapper(std::unique_ptr<FromType>& p) : from_ptr_(&p) {
        auto d = static_cast<ToType *>(p.release());
        to_ptr_ = std::unique_ptr<ToType>(d);
    }

    ~FTScopedCastWrapper() {
        auto d = static_cast<FromType *>(to_ptr_.release());
        (*from_ptr_) = std::unique_ptr<FromType>(d);
    }

    const std::unique_ptr<ToType>& operator()() {
        return to_ptr_;
    }


    // Prevent allocation on the heap
    void* operator new(size_t) = delete;
    void* operator new(size_t, void*) = delete;
    void* operator new[](size_t) = delete;
    void* operator new[](size_t, void*) = delete;

private:
    std::unique_ptr<FromType>* from_ptr_;
    std::unique_ptr<ToType> to_ptr_;
};

template <typename ToType, typename FromType>
FTScopedCastWrapper<ToType, FromType> FTScopedCast(std::unique_ptr<FromType>& p) {
    return FTScopedCastWrapper<ToType, FromType>(p);
}

然后使用预期用途

void testMethod(const std::unique_ptr<Base>& ptr) {
    // Do Stuff
}

auto ptr = std::make_unique<Derived>();
testMethod(FTScopedCast<Base>(ptr)());

删除器不会随身携带,因为这样做会阻止向上转换。 这样做也是没有意义的,因为无论如何都不会在创建的智能指针上调用删除程序。

防止在堆上进行分配,因为它可能允许包装器使用它包装的指针,并通过std :: unique_ptr成员阻止复制,并且标准销毁顺序将确保在销毁原始指针之前将其返回到原始智能指针,即使在与包装器相同的作用域中声明了它。

我知道这不是线程安全的,但我认为在线程之间共享unique_ptr违反了其与单个所有者的合同。

如果我对您的理解正确,目的是在函数调用期间“窃取” std::unique_ptr的内容,然后在函数调用完成后将其返回给其原始所有者。

但这似乎不必要地令人费解。 首先,正如@TheUndeadFish在注释中指出的那样,您可以仅使用原始的Base*作为函数参数,并使用std::unique_ptr::get()调用。 只要被调用的函数不会对传入的指针执行诸如调用delete类的愚蠢操作,或者将其松散在静态变量中以备后用,那么它将正常工作。

另外,如果您发现原始指针完全令人讨厌,则可以使用非所有者的指针包装,如下所示(未经测试,但您知道了):

template <typename T>
class unowned_ptr {
public:
    unowned_ptr() = default;
    unowned_ptr(const unowned_ptr&) = default;
    unowned_ptr& operator=(const unowned_ptr&) = default;

    template <typename U>
    unowned_ptr(const U* other) : ptr(other) {}

    template <typename U>
    unowned_ptr(const std::unique_ptr<U>& other) : ptr(other.get()) {}

    T* operator->() { return ptr; }
    const T* operator->() const { return ptr; }

private:
    T* ptr = nullptr;
};

与此非常相似的是,有人为C ++ 17提出了std::observer_ptr (“世界上最愚蠢的智能指针”),但是我不确定它的状态。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM