传递智能指针的简洁替代方案

3
我们都知道并喜欢智能指针的安全性和速度,但是必须调用像这样的函数让我感到不舒服:
void TreeNode::addChild(unique_ptr<TreeNode> newChild){
    children_.push_back(std::move(newChild));
}
//This has to be called like so:

node.addChild(unique_ptr<TreeNode>(new TreeNode(10));

我觉得这样做冗长而且过于繁琐,有没有更好的方法?我不能只传递一个原始指针并在addChild中创建我的unique_ptr吗?还有哪些替代方案和这种冗长写法的好处?
编辑:我想补充说明TreeNode可以从中派生,因此仅实现addChild(int arg)是不够的。
3个回答

4
在C++14中,您可以使用std::make_unique函数。
在C++11中,您需要自己实现它,例如:
#include <memory>

struct X { X(int, int); };

void foo(std::unique_ptr<X>);

template<class T, class... Args>
inline std::unique_ptr<T> make_unique(Args&&... args) {
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

int main() {
    foo(make_unique<X>(1, 2));
}

这只是在调用中稍微减少冗长,甚至没有触及函数声明和定义中的冗长。请记住,比较应该是调用中的普通 new 和声明中的原始指针。 - Matteo Italia
1
@MatteoItalia:从原始问题中可以看出:“...不得不调用这样的函数让我感到很烦恼...” - Maxim Egorushkin
当然,你也可以使用template<class... Args> void TreeNode::addChild(Args&&... args)重载问题中的addChild函数,实际上是将std::make_unique内联。结果为:node.addChild(10) - MSalters
@MatteoItalia 我并不在意函数定义或声明的冗长,因为我只需要写一次,并且可以添加尽可能多的注释。但是对它的调用应该是简短和清晰的。 这个解决方案中我喜欢的一件事情是,对 foo 的调用没有歧义,而且很明确地传递了一个唯一指针。 - iFreilicht
我以前从未尝试过函数模板化,但这看起来就像解决方案。我会寻找相关资料,但如果你知道好的资料也可以指给我 :) - iFreilicht
显示剩余2条评论

3
  • You may do the following:

    template<typename...Ts>
    void TreeNode::emplaceChild(Ts&&...args){
        children_.emplace_back(make_unique<TreeNode>(std::forward<Ts>(args)...));
    }
    

    And then:

    node.emplaceChild(10);
    
  • To specify the Type of child to add, you may use as replacement:

    template<typename T, typename...Ts>
    void TreeNode::emplaceChild(Ts&&...args) {
        children_.emplace_back(make_unique<T>(std::forward<Ts>(args)...));
    }
    

    And then:

    node.emplaceChild<TreeNode>(10);
    

我应该提到我想能够子类化TreeNode,抱歉。但这是目前为止最好的答案! - iFreilicht
我认为你不需要在那里使用 emplace_back - MSalters
1
这是非常奇怪的语法,我似乎还无法完全理解它... - iFreilicht
好的,我在你的答案中编辑了一个更简单的例子并接受了它,它确实帮了我很多!非常感谢! - iFreilicht

0
你可以使用一个 typedef(在 C++11 中被 using 替代):
using TreeNodeUP = std::unique_ptr<TreeNode>;

为了简化一些代码:

void TreeNode::addChild(TreeNodeUP newChild);

如果您可以控制类型TreeNode,则另一种选择是将typedef放在类内部,并将其命名为UP或类似的简短名称,然后使用它。

void TreeNode::addChild(TreeNode::UP newChild);

请注意,我个人不喜欢那些类型定义(typedef),我更喜欢详细拼写出std::unique_ptr的版本,我并没有真的发现它是一个真正的问题。

我非常喜欢typedef,但这似乎减少了声明/定义的冗长程度,而不是我所追求的调用中的冗长程度。定义的冗长程度对于自我文档化很有好处,而且我只需要编写一次。 - iFreilicht

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接