只是漏水?还是未定义的行为?
Just leaking? Or undefined behavior?
在旧的连接池实现中,我发现了这个美(强烈简化):
#include <memory>
#include <queue>
struct Connection
{
};
auto pool = std::queue<std::shared_ptr<Connection>>{};
auto pushConnection(Connection* connection) -> void
{
// This uses pushConnection as custom deleter in the shared_ptr
pool.emplace(connection, pushConnection);
}
int main()
{
pushConnection(new Connection{});
}
最初的想法是您可以从池中获取连接,完成后,自定义删除器 (pushConnection
) 会自动 return 将其添加到池中。
然而,使用相同的自定义删除器将连接存储在池中不仅仅是有点奇怪。
至少存在资源泄漏:当池在程序结束时超出范围时,将调用 queue
的析构函数。这将破坏 shared_ptr
s,这将调用他们的自定义删除器,它将连接放回队列中。
我想知道,将 emplace
变成一个当前正在被销毁的 queue
是否也是未定义的行为?
正如我评论的那样,内存泄漏源于 new Connection{}
。
程序是UB吗?我觉得是这样的。
std::queue
使用 std::deque
作为默认容器。
The documentation of std::deque::emplace
说:"All iterators, including the past-the-end iterator, are invalidated."
由于 std::deque
的析构函数遍历元素,因此结果必须是 UB。
在旧的连接池实现中,我发现了这个美(强烈简化):
#include <memory>
#include <queue>
struct Connection
{
};
auto pool = std::queue<std::shared_ptr<Connection>>{};
auto pushConnection(Connection* connection) -> void
{
// This uses pushConnection as custom deleter in the shared_ptr
pool.emplace(connection, pushConnection);
}
int main()
{
pushConnection(new Connection{});
}
最初的想法是您可以从池中获取连接,完成后,自定义删除器 (pushConnection
) 会自动 return 将其添加到池中。
然而,使用相同的自定义删除器将连接存储在池中不仅仅是有点奇怪。
至少存在资源泄漏:当池在程序结束时超出范围时,将调用 queue
的析构函数。这将破坏 shared_ptr
s,这将调用他们的自定义删除器,它将连接放回队列中。
我想知道,将 emplace
变成一个当前正在被销毁的 queue
是否也是未定义的行为?
正如我评论的那样,内存泄漏源于 new Connection{}
。
程序是UB吗?我觉得是这样的。
std::queue
使用 std::deque
作为默认容器。
The documentation of std::deque::emplace
说:"All iterators, including the past-the-end iterator, are invalidated."
由于 std::deque
的析构函数遍历元素,因此结果必须是 UB。