使用std::dynamic_pointer_cast触发段错误,求原因解析
问题分析与解决
你的代码触发段错误的核心原因是对象切片导致std::dynamic_pointer_cast转型失败返回nullptr,随后你直接对空指针调用成员函数引发了未定义行为。
具体问题拆解
我们先看关键的一行代码:
std::shared_ptr<foo> fptr = std::make_shared<foo>(b);
这里你用bar类型的对象b去构造一个foo类型的对象,因为bar是foo的子类,C++会执行对象切片操作:它只会把b中属于基类foo的成员(也就是x)拷贝到新创建的foo对象里,完全丢弃bar特有的成员y。最终fptr指向的是一个纯粹的foo对象,和原来的bar对象没有任何关系。
而std::dynamic_pointer_cast的作用是在继承体系中做安全的向下转型,它要求被转型的指针实际指向的是目标子类类型的对象。现在fptr指向的是foo对象,不是bar对象,所以转型失败,返回nullptr。
接下来你直接执行:
std::cout << (std::dynamic_pointer_cast<bar>(fptr))->get_x();
对nullptr调用->操作符属于未定义行为,这就是段错误的直接原因。
修复方案
1. 避免对象切片,让智能指针实际指向bar对象
如果你想通过基类智能指针管理子类对象,应该直接创建子类的shared_ptr再赋值给基类指针:
std::shared_ptr<foo> fptr = std::make_shared<bar>(0.5);
这样fptr指向的实际是bar对象,std::dynamic_pointer_cast<bar>就能成功返回有效的智能指针。
2. 始终检查转型结果是否有效
不管什么时候使用dynamic_pointer_cast,都应该先检查返回值是否为nullptr,避免空指针访问:
if (auto bar_ptr = std::dynamic_pointer_cast<bar>(fptr)) { std::cout << bar_ptr->get_x() << std::endl; } else { std::cout << "Failed to cast to bar!" << std::endl; }
完整修复后的代码
#include <iostream> #include <memory> class foo { private: int x; public: foo() : x(0) {} foo(int xx) : x(xx) {} virtual ~foo() = default; int get_x() const { return x; } }; class bar : public foo { private: double y; public: bar(double yy) : foo(), y(yy) {} double get_y() const { return y; } }; int main(void) { std::shared_ptr<foo> fptr = std::make_shared<bar>(0.5); if (auto bar_ptr = std::dynamic_pointer_cast<bar>(fptr)) { std::cout << bar_ptr->get_x(); } else { std::cout << "Cast failed!" << std::endl; } return 0; }
内容的提问来源于stack exchange,提问作者sjrowlinson
相关产品推荐
相关产品推荐

