使用类型转换创建对 unique_ptr 中对象的引用
Create reference to object in unique_ptr with typecast
我发现我仍然用 C 风格做很多令人尴尬的事情,所以我现在正试图通过减少对原始指针的使用来迎接新的千年。我有一个 unique_ptr<BaseClass>
的向量,每个向量都指向派生 class 的一个对象。我试图找到一种很好的方法来引用派生 class 的对象之一。目前,我通过使用 .get()
函数并将其转换为派生的 class 来完成此操作。
然而,据我了解,.get()
主要用于与坚持使用原始指针的遗留代码交互,应避免使用它。如果可以避免的话,在 unique_ptr
中有另一个指向对象的指针似乎不是很好的风格。有没有办法在不使用 get 的情况下获取对派生 class 对象的引用?或者其他一些处理对象的方便方法?
这是一个简化的代码示例:
#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> 的答案概述了 "cast" unique_ptr
的方法,方法是释放它并为派生的 class 重新创建一个新的 unique_ptr
,但是这在这里似乎不适用,因为我真的不想弄乱唯一指针的向量(除非我遗漏了什么)。
如果你知道指针是非nullptr
,一个更简单的转换是:
auto& apple = static_cast<Apple&>(*apples[0]);
此语法适用于所有支持 T& operator*() const
的智能指针(例如 std::unique_ptr
、std::shared_ptr
、boost::intrusive_ptr
)。
在多重继承的情况下,from-base-reference-to-derived-reference 比转换 from-base-pointer-to-derived 更快-pointer 因为后者必须在向指针添加或减去偏移量之前始终检查 nullptr
(以便 nullptr
在转换后变为 nullptr
),而引用不能 nullptr
,因此不需要 运行 时间检查。
一个更安全的替代方法是定义一个辅助函数
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));
我发现我仍然用 C 风格做很多令人尴尬的事情,所以我现在正试图通过减少对原始指针的使用来迎接新的千年。我有一个 unique_ptr<BaseClass>
的向量,每个向量都指向派生 class 的一个对象。我试图找到一种很好的方法来引用派生 class 的对象之一。目前,我通过使用 .get()
函数并将其转换为派生的 class 来完成此操作。
然而,据我了解,.get()
主要用于与坚持使用原始指针的遗留代码交互,应避免使用它。如果可以避免的话,在 unique_ptr
中有另一个指向对象的指针似乎不是很好的风格。有没有办法在不使用 get 的情况下获取对派生 class 对象的引用?或者其他一些处理对象的方便方法?
这是一个简化的代码示例:
#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> 的答案概述了 "cast" unique_ptr
的方法,方法是释放它并为派生的 class 重新创建一个新的 unique_ptr
,但是这在这里似乎不适用,因为我真的不想弄乱唯一指针的向量(除非我遗漏了什么)。
如果你知道指针是非nullptr
,一个更简单的转换是:
auto& apple = static_cast<Apple&>(*apples[0]);
此语法适用于所有支持 T& operator*() const
的智能指针(例如 std::unique_ptr
、std::shared_ptr
、boost::intrusive_ptr
)。
在多重继承的情况下,from-base-reference-to-derived-reference 比转换 from-base-pointer-to-derived 更快-pointer 因为后者必须在向指针添加或减去偏移量之前始终检查 nullptr
(以便 nullptr
在转换后变为 nullptr
),而引用不能 nullptr
,因此不需要 运行 时间检查。
一个更安全的替代方法是定义一个辅助函数
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));