这是使用XCode C ++语言方言c ++ 1y。帮我理解unique_ptr:
//1
auto ouput2 = make_unique<standard::Algorithm>(AlgorithmFactory::create("YamlOutput",
"filename", outputFilename));
//2
unique_ptr<standard::Algorithm> output(standard::AlgorithmFactory::create("YamlOutput",
"filename", outputFilename));
1失败,构建时出现“语义问题:分配抽象类类型的对象'essentia :: standard :: Algorithm',但是2成功。
我read这两个是等价的,那么怎么会成功而另一个不成功呢?
我查看AlgorithmFactory :: create()的源代码,它根据字符串输入返回BaseAlgorithm *。因为标准:: Algorithm似乎与BaseAlgorithm没有任何关系(它没有扩展它),所以并不真正理解对象层次结构。
这就是我使用的Essentia库的文档是如何做到的,除非他们使用的是裸指针。
答案 0 :(得分:4)
它们并不等同。 make_unique
创建对象,而unique_ptr
只包含现有指针。
您的第一行相当于unique_ptr<standard::Algorithm>(new standard::Algorithm(AlgorithmFactory::create(...)))
。请注意此处使用new
。
答案 1 :(得分:3)
这两个陈述并不等同。区别在于:
您的第二个版本是通过提供现有的原始指针来调用unique_ptr
构造函数。它只将该对象指针封装在unique_ptr
。
第一个版本应该为您的对象提供构造函数参数,它将以安全的方式为您创建对象。它构造并封装了unique_ptr
。
问题是您的工厂已经分配了对象并返回一个原始指针。那时使用make_unique
就没有意义,因为该函数的目的是避免完全处理原始指针,即一次性构造和包装。
这里有两个选项:
坚持你的第二个版本。
更改工厂,使其在其实施中使用unique_ptr
返回make_unique
。但是提供同一工厂的shared_ptr
版本也是有意义的。像createUnique
+ createShared
这样的东西,也许保留现有的create
返回原始指针。这是代码风格的问题。
答案 2 :(得分:1)
std::make_unique<T>
将其参数转发给T
的构造函数并构造一个新的T
,然后创建一个指向新构造的std::unique_ptr<T>
的{{1}}。如果T
是一个抽象类,那么这肯定会失败。即使T
不是抽象类,也可能无法编译,因为T
函数可能会返回AlgorithmFactory::create
。另一方面,T*
的构造函数采用可转换为std::unique_ptr<T>
的参数,并且没有问题。