数据库连接池的std :: stack中的原始指针或std :: shared_ptr

时间:2016-01-09 13:58:59

标签: c++ pointers c++11 stack shared-ptr

我搜索了谷歌和stackoverflow但没有找到我的特定用法的答案。关于原始指针和std :: shared_ptr的优点有很多很好的建议,但与std :: stack无关。

我看过Herb Sutters在youtube上谈论编写好的C ++ 14代码(https://www.youtube.com/watch?v=hEx5DNLWGgA),一个主题就是为什么唯一和共享指针很有用。

所以我将简单的数据库连接池从原始指针重写为std :: shared_ptr。在我的top()/ pop()堆栈之后进行连接并与db交互我将它推回()。

使用构造函数中的原始指针

Database::Database(const unsigned int connections) {
    for (int i = 0; i < connections; ++i) {
        try {
            auto* dbconn = new pqxx::connection(connectionString);
            dbpool.push(dbconn);
        } catch (const std::exception& e) {
            std::cerr << e.what() << std::endl;
        }
    }
}

后来

auto *D = dbpool.top();
dbpool.pop();

std::string query = "select * from races order by racestart_at desc";
pqxx::nontransaction N(*D);
pqxx::result R(N.exec(query));

dbpool.push(D);

在构造函数中使用shared_ptr

auto* dbconn = new pqxx::connection(connectionString);
std::shared_ptr<pqxx::connection> s_dbconn(dbconn);
dbpool.emplace(s_dbconn);

在程序中

auto D = dbpool.top();
dbpool.pop();
<query db etc.>
dbpool.push(D);

在这种情况下,原始指针和共享指针一样好吗?我没有看到原始指针在许多地方误入歧途。

3 个答案:

答案 0 :(得分:2)

关于所有权。使用共享指针,其中多个代码(对象)可以同时拥有指针。

对于你的游泳池示例,最好只创建一个连接对象的数组(std :: array或std :: vector),并指定另一个数组(或你的情况下是堆栈) (或索引)到第一个数组中的对象。然后,当从池请求连接对象时,您将返回一个作为原始指针,然后您需要一个函数来&#34;返回&#34;连接回池,以便可以重复使用。

通过这种方式,只有池实际拥有连接对象,因此它应该是唯一一个删除它们的对象。其他代码只使用该对象但不应删除它,而是应该在完成使用后将其返回到池中。

增强此功能的一种方法是从池中返回特殊对象/类而不是原始指针。这个对象就像一个管理连接对象贷款的小RAII包装器。因此它被销毁它将连接对象返回到池中。我相信您可以将unique_ptr与自定义删除器一起用于此目的。

答案 1 :(得分:2)

由于当有人请求资源时你实际上从池中删除了指针,因此智能指针肯定你应该做什么。原因是您无法删除析构函数中的所有资源,因为您没有始终可用的所有指针。

如果要使用原始指针,则应始终将所有指针保留在类中,以便在数据库被销毁时删除它们。这需要重新设计,以便将各个资源标记为已占用/自由。

那就是说 - 记住,使用池与动态内存分配相同。

如果有人忘记将资源返回池中,您的程序迟早会崩溃。

如果有人忘记删除动态分配的内存,程序迟早会崩溃。

同样的故事......

换句话说 - 池与动态内存分配一样危险。

答案 2 :(得分:-1)

原始指针可能会误入歧途,因为它们不会自动删除,并且当您认为处理完所有情况时,它们会有很多很多方法可以泄漏。