使用类型转换在unique_ptr中创建对象的引用

时间:2017-12-06 09:48:52

标签: c++ c++11 casting unique-ptr

我发现我仍然用c风格做了大量令人尴尬的事情,所以我现在正试图通过减少对原始指针的使用来迎接新的千年。我有一个unique_ptr<BaseClass>的向量,每个向量都指向派生类的对象。我试图找到一个很好的方式来引用派生类的一个对象。目前,我通过使用.get()函数并将其转换为派生类来实现此目的。

但是,据我所知,.get()主要用于与遗留原始指针的遗留代码进行交互,应避免使用它。如果可以避免,在unique_ptr内使用另一个指向对象的指针似乎并不是很好的风格。有没有办法获得对派生类对象的引用,而不使用get?还是其他一些处理对象的方便方法?

这是一个简化的代码示例:

#include <iostream>
#include <vector>

class Fruit {
public:
    double size = 0;
    virtual ~Fruit() = default;
};

class Apple : public Fruit {
public:
    bool hasLeaf = false;
};

void doAppleStuff(std::vector<std::unique_ptr<Fruit> > &apples) {

    // assume we know that element [0] exists and it is definitely of type Apple
    auto apple = static_cast<Apple *> (apples[0].get());  // is there a better option?

    if (apple->hasLeaf) {
        std::cout << "We can leaf now" << std::endl;
    } else {
        std::cout << "We are pitiably leafless" << std::endl;
    }
}

int main() {
    std::vector<std::unique_ptr<Fruit> > fruitVec;
    auto apple = new Apple;
    apple->hasLeaf = true;
    std::unique_ptr<Fruit> applePt(apple);
    fruitVec.push_back(std::move(applePt));
    doAppleStuff(fruitVec);
    return 0;
}

(我认为可能用c ++ 14中的make_unique来缩短主函数。)

做这样的事情是不是很好的编码风格?

auto &apple = *static_cast<Apple *> (apples[0].get());

"Downcasting" unique_ptr<Base> to unique_ptr<Derived>的答案概述了一种方法,以及#34;施放&#34; unique_ptr通过释放它并为派生类重新创建新的unique_ptr,但这似乎并不适用于此,因为我并不想真正混淆独特的向量指针(除非我遗漏了什么)。

2 个答案:

答案 0 :(得分:2)

如果你知道指针是非nullptr,那么更简单的演员是:

auto& apple = static_cast<Apple&>(*apples[0]);

此语法适用于支持T& operator*() const的所有智能指针(例如std::unique_ptrstd::shared_ptrboost::intrusive_ptr)。

在具有多重继承的情况下, from-base-reference-to-derived-reference 比将 from-base-pointer-to-derived-pointer 更快地投射,因为后者必须在向指针添加或减去偏移量之前检查nullptr(以便nullptr在转换后变为nullptr),而引用不能是nullptr和因此,不需要运行时检查。

答案 1 :(得分:0)

更安全的替代方法是定义辅助函数

template <typename T> // 
std::vector<T *> of_type(const std::vector<std::unique_ptr<Fruit>> & fruits) {
    std::vector<T *> result;
    for (auto & ptr : fruits) {
        if (T * item = dynamic_cast<T *>(ptr.get())) {
            result.push_back(item);
        }            
    }
    return result;
}

然后将doAppleStuff更改为

void doAppleStuff(std::vector<Apple *> & apples);

称为

doAppleStuff(as_type<Apple>(fruitVec));