我不明白为什么要调用析构函数(这个调用的位置在下面的代码中)
如果调用了析构函数,为什么可以调用函数Print()
?
代码:
class Entity
{
public:
Entity()
{
std::cout << "Ctor Call" << std::endl;
}
~Entity()
{
std::cout << "Destroy Call" << std::endl;
}
void Print()
{
std::cout << "Print me" << std::endl;
}
};
int main()
{
Entity* ent;
{
std::shared_ptr<Entity>sharedPtr = std::make_shared<Entity>();
sharedPtr->Print();
ent = &(*sharedPtr);
} //after this line the destructor was call
ent->Print(); // the print is success
std::cin.get();
}
答案 0 :(得分:1)
是的,当共享指针超出范围时会调用析构函数(因此会自行销毁)。后续Print()
方法调用成功的原因是在被破坏对象上调用方法是一种未定义的行为,因此它不一定需要崩溃。对象本身仍然可以躺在那里,方法调用可能会成功,尽管绝对没有保证。在这种情况下,机会甚至更高,因为该方法实际上并未使用来自实例的任何数据,而只是调用库函数。
请注意,复制shared_ptr所持有的基础地址并不会增加其内部引用次数,因为这样做是为了规避&#34;官方&#34;事实上,从std::shared_ptr reference:
获取共享指针的副本的方法
shared_ptr
个对象只能通过复制它们的值来共享所有权:如果从同一个(非shared_ptr
)指针构造(或制作)两个shared_ptr
,它们都将拥有指针没有共享它,当其中一个释放它(删除其托管对象)并让另一个指向无效位置时,会导致潜在的访问问题。
如果通过复制shared_ptr
获得副本,则该对象不会被删除。
答案 1 :(得分:1)
为什么函数Print在没有崩溃的情况下调用
因为无法保证如果您的代码产生未定义的行为(确实如此),那么它必须崩溃。它甚至可能看起来你的程序成功,这可能是UB最糟糕的一面。
答案 2 :(得分:1)
调用析构函数是因为对象ent
是在局部作用域内创建的,所以在超出作用域之后,应该调用析构函数。有关共享指针的更多信息,请参阅this question