正如 Bjarne Stroustrup 的“C++ 之旅”中所述,并且作为一种已知的 C++14 实践,应该避免在代码中使用裸露的
new
和 delete
。标准库提供 std::make_shared
和 std::make_unique
用于创建智能指针以立即存储分配的对象。
但是,无法将这些例程用于非标准智能指针,例如在 Qt 中。 Qt 有自己的内存管理模型(有父级),但也提供了智能指针类,如
QSharedPointer
和 QPointer
(尽管后者实际上并不是拥有指针)。
我的问题是:创建
std::make_shared
的 Qt 类似物不是很方便吗?像这样,创建QSharedPtr
:
namespace Qt
{
template<class T, class... Args>
QSharedPointer<T> make_shared(Args&&... args)
{
return QSharedPointer<T>(new T(std::forward<Args>(args)...));
}
}
或者像这样,用于创建
QPointer
:
namespace Qt
{
template<class T, class... Args>
QPointer<T> make_ptr(Args&&... args)
{
return QPointer<T>(new T(std::forward<Args>(args)...));
}
}
它可以像这样使用:
auto pCancelButton = Qt::make_ptr<QPushButton>("Cancel", this);
这种方法有什么注意事项吗?这种方法有任何公开的用法吗?
更新我声称只要
Qt::make_ptr
有用,QPointer
就有用,因为它将隐藏new
运算符并确保仅对继承new
的东西调用QObject
。 Qt 用户做了很多 new
,但通过这种方式我们可以确定 new
仅在 Qt 上下文中使用。对于这个想法有什么争论吗?
make_shared
等功能严格依赖于完美转发功能,该功能自C++11以来才可用并引入了通用(转发)引用。话虽如此,如果没有完美的转发,使用这个功能可能效率很低。 Qt 比最近的 C++ 标准要老得多,因此直到 Qt 5.1 才可用(就像以前一样,您必须使用 Qt 的内部预处理宏,如 SIGNAL
和 SLOT
来建立连接)。
Qt 5.1 已经提供了自己的实现来为 QSharedPointer制作智能指针。
create
成员函数可以按如下方式使用:
auto ptr = QSharedPointer<QPushButton>::create("Cancel", this);
但请注意描述:
注意:此函数仅适用于支持任意数量参数完美转发的C++11编译器。如果编译器不支持必要的 C++11 功能,则必须使用调用默认构造函数的重载。
使用
make_shared
和 create
函数比直接调用构造函数并使用 new
分配内存有两大优点:
特殊的完美转发函数可以在单个系统调用中为存储对象和引用计数器分配内存。
内存分配与调用上下文分离,因此可以避免在构造另一个对象时引发异常时发生内存泄漏。函数调用(编译器可以自由选择参数的计算顺序)。考虑:
foo(QSharedPointer<QPushButton>(new QPushButton("Cancel", this)), MayThrow());
也就是说,如果编译器首先执行
new QPushButton("Cancel", this)
表达式,然后在调用MayThrow()
的构造函数之前调用QSharedPointer
函数,那么如果MayThrow()
函数抛出异常,则可能会泄漏内存。