C++带有unique_ptr的堆栈

4
我有一个遗留的程序,它使用std::stack对象来存储一些指针。
std::stack<Widget*> widgetStack;

现在我想将这个代码更改为新的C++11风格。
std::stack<std::unique_ptr<Widget>> widgetStack;

然而在代码中有一个函数:

Widget* getLastWidget()
{
    if(!widgetStack.isEmpty())
    {
        return widgetStack.top();
    }
    return null;
}

我正在努力让这个函数与unique_ptr一起工作。栈是小部件的所有者,只有在弹出栈时,Widget对象才应该被销毁。您有什么关于如何解决这个问题的想法吗?


3
你可以使用.get()方法。 - Passer By
1
然后使用 std::shared_ptrstd::weak_ptr。你正在使用错误的工具... - user202729
1
std::stack::top 返回栈顶对象的引用。例如,您可以在函数中返回 std::unique_ptr<Widget>& - Yksisarvinen
2
如果你想在不从堆栈中移除顶部对象的情况下使用它,那么 Passer By 建议使用 .get() 是一个不错的选择。 - Ben Voigt
1
@Frank 根据cppreference的说法,它会引发未定义行为 - Yksisarvinen
显示剩余4条评论
2个回答

8

如果栈是指针的唯一所有者,则建议返回原始指针,因为原始指针表示“没有所有权的指针”:

Widget* getLastWidget()
{
    if(!widgetStack.isEmpty())
    {
        return widgetStack.top().get();
    }
    return nullptr;
}

2

个人不太喜欢使用原始指针。你可以像@user202729建议的那样,将std::unique_ptr简单地更改为std::shared_ptr

std::stack<std::shared_ptr<Widget>> widgetStack;

std::shared_ptr<Widget> getLastWidget()
{
    if(!widgetStack.isEmpty())
    {
        return widgetStack.top();
    }
    return nullptr;
}

这样指针仍然由堆栈管理,您不必以原始形式处理它们。
我在评论中建议使用引用,但这并不是很好的解决方案。返回引用会使得返回空堆栈指示变得困难(例如您示例中的nullptr)。

2
请注意,函数返回的所有shared_ptr都具有共享所有权,这意味着即使从堆栈中pop出元素,它也不一定会被销毁。 - jotasi
的确,我也考虑过这个问题。但正如@jotasi所指出的那样,这违背了我希望堆栈拥有对象的愿望。 - Frank
1
@Frank 如果这是你想要的,那么这不是正确的解决方案。但是你必须小心应用另一个解决方案,返回一个原始指针,因为在那里,当元素被“pop”时,指针将会悬空,并且你无法真正检查是否发生了这种情况... - jotasi
2
我明白了。在这种情况下,原始指针可能是最合理的解决方案。但是要小心,因为堆栈上的指针可能在您仍在使用它时被弹出。 - Yksisarvinen
除非您确定需要共享所有权,否则产生“shared_ptr”的开销并不值得相比使用“unique_ptr”带来的轻微方便。 - Rotsiser Mho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接