在动态创建的智能指针向量元素上投射 static_cast
Casting static_cast on dynamically-created element of smartpointers vector
我正在学习 C++,但遇到了一个问题。我创建了一个智能指针向量,其中包含派生 class 的动态创建对象,但我无法在这些对象之一上投射 static_cast。我尝试了几种方法,但都没有用。
这是我的代码:
class Person {};
class Walker : public Person {};
std::vector<std::unique_ptr<Person>>v1;
for (int i = 0; i < 4; i++) { v1.push_back(std::unique_ptr<Person>(new Walker) ); }
//trying to cast static_cast on element on position 1:
std::unique_ptr<Person>ptr = move(v1[1]);
auto walkers = static_cast<Walker*>(ptr);//doesnt work - no suitable conversion function
这可能不是您想要的!
Person
class 应该有一个 Walker
实现的虚拟接口,因此您不需要将 Person 指针转换为 Walker 指针。
也就是说:
解决您当前的问题:
std::unique_ptr<Walker> getWalkerFromPerson(std::unique_ptr<Person> person)
{
// Note there is still an issue here.
// If this is not a Walker then it will leak
// the person as dynamic_cast will give you a nullptr
return std::unique_ptr<Walker>(dynamic_cast<Walker*>(person.release()));
}
然后这样调用:
auto walkers = getWalkerFromPerson(std::move(v1[0]));
一些建议:
- 您需要释放
person
(因此它不会删除它)。
- 您需要使用
dynamic_cast
(从父类型转换为未知(运行-时间已知)子类型)。
您不能强制转换 std::unique_ptr
,但您可以为其托管指针执行此操作:
auto* walkers = static_cast<Walker*>(ptr.get());
您需要先从 unique_ptr
中解包原始指针:
auto walkers = static_cast<Walker*>(ptr.get());
注意指针的所有权仍然属于ptr
,也就是std::unique_ptr<Person>
。您可以这样转让所有权:
std::unique_ptr<Walker> walkers(static_cast<Walker*>(ptr.release()));
如果你愿意,你可以这样写一个函数
template<typename Target, typename Source>
auto static_cast_unique(std::unique_ptr<Source> ptr) {
return std::unique_ptr<Target>(static_cast<Target*>(ptr.release()));
}
所以你可以这样写
auto walkers = static_cast_unique<Walker>(std::move(v1[1]));
现在,您的代码存在一些问题:
Person
需要一个虚拟析构函数。您有 Walker
个对象,属于 std::unique_ptr<Person>
个。这本身没问题,但是当那些 unique_ptr
试图销毁他们的对象时,他们会调用 ~Person
,而不是 ~Walker
(因为这是他们的类型要求做的),这将是UB。给 Person
一个 virtual ~Person()
(并且 Walker
将继承 virtual
ness)
class Person { public: virtual ~Person() = default; };
class Walker : public Person {};
std::unique_ptr(new ...)
最好写成std::make_unique
for (int i = 0; i < 4; i++) v1.push_back(std::make_unique<Walker>());
std::unique_ptr
s 会自动向上转换。
在这种情况下,使用 static_cast
似乎没问题,因为您 知道 您实际指向的 Person*
一个Walker
。但是,在一般情况下您会希望使用 dynamic_cast
,这样您就可以检测到对象 何时不是您期望的类型 。我会使用这样的函数
template<typename Target, typename Source>
std::unique_ptr<Target> dynamic_cast_unique(std::unique_ptr<Source> &&ptr) {
if(auto ret = dynamic_cast<Target*>(ptr.get())) {
ptr.release();
return std::unique_ptr<Target>(ret);
} else return nullptr;
}
哪个用的像
auto walkers = dynamic_cast_unique<Walker>(std::move(v1[1]));
如果成功,walkers
将拥有之前由 v1[1]
拥有的对象,而 v1[1]
将为空。否则,walkers
为空,v1[1]
不变。
我正在学习 C++,但遇到了一个问题。我创建了一个智能指针向量,其中包含派生 class 的动态创建对象,但我无法在这些对象之一上投射 static_cast。我尝试了几种方法,但都没有用。
这是我的代码:
class Person {};
class Walker : public Person {};
std::vector<std::unique_ptr<Person>>v1;
for (int i = 0; i < 4; i++) { v1.push_back(std::unique_ptr<Person>(new Walker) ); }
//trying to cast static_cast on element on position 1:
std::unique_ptr<Person>ptr = move(v1[1]);
auto walkers = static_cast<Walker*>(ptr);//doesnt work - no suitable conversion function
这可能不是您想要的!
Person
class 应该有一个 Walker
实现的虚拟接口,因此您不需要将 Person 指针转换为 Walker 指针。
也就是说:
解决您当前的问题:
std::unique_ptr<Walker> getWalkerFromPerson(std::unique_ptr<Person> person)
{
// Note there is still an issue here.
// If this is not a Walker then it will leak
// the person as dynamic_cast will give you a nullptr
return std::unique_ptr<Walker>(dynamic_cast<Walker*>(person.release()));
}
然后这样调用:
auto walkers = getWalkerFromPerson(std::move(v1[0]));
一些建议:
- 您需要释放
person
(因此它不会删除它)。 - 您需要使用
dynamic_cast
(从父类型转换为未知(运行-时间已知)子类型)。
您不能强制转换 std::unique_ptr
,但您可以为其托管指针执行此操作:
auto* walkers = static_cast<Walker*>(ptr.get());
您需要先从 unique_ptr
中解包原始指针:
auto walkers = static_cast<Walker*>(ptr.get());
注意指针的所有权仍然属于ptr
,也就是std::unique_ptr<Person>
。您可以这样转让所有权:
std::unique_ptr<Walker> walkers(static_cast<Walker*>(ptr.release()));
如果你愿意,你可以这样写一个函数
template<typename Target, typename Source>
auto static_cast_unique(std::unique_ptr<Source> ptr) {
return std::unique_ptr<Target>(static_cast<Target*>(ptr.release()));
}
所以你可以这样写
auto walkers = static_cast_unique<Walker>(std::move(v1[1]));
现在,您的代码存在一些问题:
Person
需要一个虚拟析构函数。您有Walker
个对象,属于std::unique_ptr<Person>
个。这本身没问题,但是当那些unique_ptr
试图销毁他们的对象时,他们会调用~Person
,而不是~Walker
(因为这是他们的类型要求做的),这将是UB。给Person
一个virtual ~Person()
(并且Walker
将继承virtual
ness)class Person { public: virtual ~Person() = default; }; class Walker : public Person {};
std::unique_ptr(new ...)
最好写成std::make_unique
for (int i = 0; i < 4; i++) v1.push_back(std::make_unique<Walker>());
std::unique_ptr
s 会自动向上转换。在这种情况下,使用
static_cast
似乎没问题,因为您 知道 您实际指向的Person*
一个Walker
。但是,在一般情况下您会希望使用dynamic_cast
,这样您就可以检测到对象 何时不是您期望的类型 。我会使用这样的函数template<typename Target, typename Source> std::unique_ptr<Target> dynamic_cast_unique(std::unique_ptr<Source> &&ptr) { if(auto ret = dynamic_cast<Target*>(ptr.get())) { ptr.release(); return std::unique_ptr<Target>(ret); } else return nullptr; }
哪个用的像
auto walkers = dynamic_cast_unique<Walker>(std::move(v1[1]));
如果成功,
walkers
将拥有之前由v1[1]
拥有的对象,而v1[1]
将为空。否则,walkers
为空,v1[1]
不变。