简体   繁体   English

使用typecast在unique_ptr中创建对对象的引用

[英]Create reference to object in unique_ptr with typecast

I find I still do an embarrassingly large number of things in c style, so I am now trying to embrace the new millennium by reducing my usage of raw pointers. 我发现我仍然用c风格做大量令人尴尬的事情,因此我现在正尝试通过减少对原始指针的使用来迎接新的千年。 I have a vector of unique_ptr<BaseClass> , that each points to an object of a derived class. 我有一个unique_ptr<BaseClass>向量,每个向量都指向派生类的对象。 I am trying to get a nice way to refer to one of the objects of the derived class. 我试图获得一种很好的方法来引用派生类的对象之一。 At the moment, I do this by using the .get() function and casting this to the derived class. 目前,我通过使用.get()函数并将其转换为派生类来实现。

However, as I understand it, .get() is mostly there to interface with legacy code that insists on raw pointers, and its use should be avoided. 但是,据我了解, .get()大部分用于与坚持使用原始指针的旧代码进行接口,因此应避免使用它。 Having another pointer to an object within a unique_ptr doesn't seem like great style if it can be avoided. 如果可以避免的话,在unique_ptr中拥有另一个指向对象的指针似乎不是很棒的样式。 Is there a way to get a reference to the derived class object, without using get? 有没有一种方法可以在不使用get的情况下获取对派生类对象的引用? Or some other convenient way of handling the object? 还是一些其他方便的方式来处理对象?

Here is a simplified code example: 这是一个简化的代码示例:

#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;
}

(I think that it's probably possible to shorten the main function with make_unique from c++14). (我认为使用c ++ 14中的make_unique可能会缩短main函数)。

Would it be good coding style to do something like this? 做这样的事情会是好的编码风格吗?

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

The answer at "Downcasting" unique_ptr<Base> to unique_ptr<Derived> outlines a method to "cast" the unique_ptr by releasing it and recreating a new unique_ptr to the derived class, but that doesn't seem applicable here, as I don't really want to mess with the vector of unique pointers (unless I am missing something). “ unicast_ptr <基本>“向下转换”到unique_ptr <Derived>的答案概述了一种方法,该方法通过释放它并为派生类重新创建一个新的unique_ptr来“铸造” unique_ptr ,但这似乎不适用于这里,因为我没有我真的很想弄乱唯一指针的向量(除非我错过了什么)。

If you know that the pointer is non- nullptr , a simpler cast is: 如果您知道指针为非nullptrnullptr简单的转换为:

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

This syntax works with all smart-pointers that support T& operator*() const (eg std::unique_ptr , std::shared_ptr , boost::intrusive_ptr ). 此语法适用于所有支持T& operator*() const智能指针(例如std::unique_ptrstd::shared_ptrboost::intrusive_ptr )。

In cases with multiple inheritance casting from-base-reference-to-derived-reference is faster than casting from-base-pointer-to-derived-pointer because the latter must always check for nullptr before adding or subtracting an offset to the pointer (so that nullptr turns into nullptr after the cast), whereas references cannot be nullptr and therefore no run-time check is necessary. 在具有多重继承的情况下, 从基础引用到源引用的转换比从基础指针到源指针的转换更快,因为后者必须在添加或减去指针的偏移量之前始终检查nullptr (因此nullptrnullptr转换后变成nullptr ),而引用不能为nullptr ,因此不需要运行时检查。

A safer alternative is to define a helper function 一个更安全的选择是定义一个辅助函数

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;
}

and then change doAppleStuff to 然后将doAppleStuff更改为

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

called as 称为

doAppleStuff(as_type<Apple>(fruitVec));

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

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