用什么替代std::map::emplace?

4
对于容器,例如std::map< std::string, std::unique_ptr< Foo >>,就目前而言,在gcc 4.7.2中,似乎尚未实现emplace()

不幸的是,我无法直接通过值存储Foo,因为它是一个抽象超类。

作为一个简单但低效的占位符,我一直在使用std::map< std::string, Foo* >std::vector< std::unique_ptr< Foo >> 以进行垃圾回收。

你是否有更高效且更易于替换的中间解决方案,等到emplace()可用时再进行替换?

2个回答

11
你为什么需要emplace()?只需将其移入即可:
#include <iostream>
#include <map>
#include <memory>
#include <string>

struct Foo
{
    virtual ~Foo() = default;

    virtual std::string name() const = 0;
};

struct Bar : Foo
{
    std::string name() const { return "Bar"; }
};

int main()
{
    std::map<std::string, std::unique_ptr<Foo>> m;

    std::unique_ptr<Foo> p(new Bar());
    m.insert(std::make_pair("a", std::move(p)));

    std::cout << m["a"]->name() << std::endl;
}

事实上,你不应该使用emplace来处理unique_ptr
正如我在评论中指出的那样,我现在认为在用户代码中使用new是一个错误。它应该被替换为make_unique,这样你就知道你的资源不可能泄漏:
// will be in std:: someday
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

int main()
{
    std::map<std::string, std::unique_ptr<Foo>> m;

    m.insert(std::make_pair("a", make_unique<Bar>()));

    std::cout << m["a"]->name() << std::endl;
}

一个好的答案并附上可用代码将会得到加分。避免在用户代码中使用 new 是一项值得称赞的事业。但是,假设我需要插入一个 foo->clone() 到 map 中,因为我不知道我有什么样的 Foo,而不是构造一个新的 Bar 实例,你会如何使 Foo* Bar::clone() 避免调用 new?或者这样做是否可以,因为它不会被视为客户端代码? - kfmfe04
1
恰巧今天我刚处理过这个问题。让你的克隆函数返回 std::unique_ptr<Foo> - GManNickG
我知道这有点老了,但是如果foo->clone()的用户想要一个shared_ptr怎么办? - Dalibor Frivaldsky
@DaliborFrivaldsky:你可以从unique_ptr构造一个shared_ptr。 - GManNickG

2
作为解决方法,您可以使用支持大多数C++ 11功能甚至在C++ 03编译器下也具有与std容器相同布局的boost容器,然后当您在std中具有该功能时,只需切换名称空间即可!

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