说我有一个对象:
struct Foo {
Foo(const std::string& str1, const std::string& str1)
: mStr1(str1), mStr2(str2)
{}
std::string mStr1;
std::string mStr2;
};
并设置
typedef std::unordered_set<std::shared_ptr<Foo> , Hash, Compare> Set;
我有自定义哈希并进行比较。但是当我说:
Set set;
set.emplace(str1, str2);
我收到编译错误,因为Foo
的构造函数显然不是std::shared_ptr<Foo>
的构造函数。我想要的是当emplace需要构造一个使用std::make_shared<Foo>(str1, str2)
似乎我还需要一个自定义分配器,但我没有设法实现满足编译器的分配器。
我的问题是:我想要的是什么。如果是,那么分配器是如何正确的。如果是的话,你能指点我一个例子。
答案 0 :(得分:1)
使用set.insert(std::make_shared<Foo>(str1, str2));
。对于具有唯一键的容器,emplace
通常不是一个好处,因为重复键是一个问题,因为它的运行方式:
emplace
没有可靠的方法来检测可以复制或移动某些内容,因为is_copy_constructible
返回{{1}有很多类型但是无法实际复制。 true
的典型实现因此总是为节点预先分配内存,构造该内存中的对象,将其与容器中的现有元素进行比较,然后将其链接,或者将其销毁,释放记忆。
emplace
有密钥随时可用。因此,它可以首先决定是否应插入节点,并且只应分配内存。
理论上,实现可能是特殊情况insert
用于&#34;一个参数类型与元素类型相同&#34;案件。但我知道实际上并没有实现这一点。
答案 1 :(得分:0)
我收到编译错误,因为Foo的构造函数很明显 不是std :: shared_ptr的构造函数。我想要的是什么时候 emplace需要构造一个使用指针 std :: make_shared(str1,str2)
emplace
实现为一个函数,它使用完美转发来调用包含元素的构造函数(在本例中为shared_ptr)。包含的元素的构造函数接受一个指向Foo的指针,因此你应该能够这样做(就像你构造一个shared_ptr<Foo>
对象一样):
set.emplace(new Foo("x", "y")); //or
set.emplace(new Foo(str1, str2));
似乎我还需要一个自定义分配器,但我没有 设法实现一个满足编译器的。
如果您想要做的就是以最有效的方式添加shared_ptr(通过在某些预分配元素上调用转发构造函数),或者我完全误解了您的问题,那么自定义分配器总是过度杀伤。如果您不希望使用默认分配器(使用operator new)构造元素,则通常会使用分配器。在这种情况下,shared_ptr本身将是将在堆上构造的元素。如果您担心堆分配由于某种原因而无法满足您的目的(例如,如果您分配了数百万个小对象),则只能使用分配器。
注意(正如@Yakk所评论的),在这种情况下,shared_ptr的实例化可能会抛出(我只能将bad_alloc视为可能),在这种情况下,传递给emplace的指针会导致泄漏。出于这个原因,我也认为std :: make_shared会是一个更好的选择(如另一个答案所述)。
答案 2 :(得分:0)
您可以直接在std::make_shared
的参数列表中使用emplace
。
set.emplace(std::make_shared<Foo>(str1, str2));
无需自定义分配器。