正如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上下文。关于这个想法的任何争论?
答案 0 :(得分:12)
make_shared
等功能严格依赖于完美转发功能,该功能仅在C ++ 11和通用(转发)引用。话虽如此,如果没有完美转发,使用此功能可能效率低下。 Qt比最近的C ++标准要老,因此直到Qt 5.1才可用(就像以前你必须使用Qt的内部预处理宏,如SIGNAL
和SLOT
来建立连接)。 / p>
Qt 5.1已经提供了自己的实现,可以为QSharedPointer制作智能指针。
静态create
成员函数可以按如下方式使用:
auto ptr = QSharedPointer<QPushButton>::create("Cancel", this);
但请注意说明:
注意:此函数仅适用于支持完全转发任意数量参数的C ++ 11 编译器。如果编译器不支持必要的C ++ 11功能,则必须使用调用默认构造函数的重载。
使用make_shared
和create
函数有两个主要优点,而不是直接使用new
分配内存来调用构造函数:
特殊的完美转发功能可以在单个系统中分配,为存储对象和引用计数器调用内存。 / p>
内存分配与调用上下文分离,因此如果在构建另一个对象时抛出异常,则可以避免内存泄漏。函数调用(编译器可以自由选择评估参数的顺序)。考虑:
foo(QSharedPointer<QPushButton>(new QPushButton("Cancel", this)), MayThrow());
也就是说,如果编译器首先执行new QPushButton("Cancel", this)
表达式,然后在调用MayThrow()
的构造函数之前调用QSharedPointer
函数,则MayThrow()
可能会泄漏内存函数抛出异常。