插入包含 unique_ptr 的对象时,c++ map insert 无法编译
c++ map insert fails to compile when inserting an object that contains a unique_ptr
我在(编译时,gcc 17)在包含 unique_ptr 的 std::map 中插入对象时遇到问题。如果我使用常规指针,它会编译(如果我取出复制构造函数!)。
这是包含 unique_ptr 的结构。使用构造函数、复制构造函数等,到处都有 std::move 语义。有人以前见过这个问题吗?
#include <utility> // std::pair, std::make_pair
#include <string> // std::string
#include <iostream> // std::cout
#include <map>
#include <memory>
struct Struct1
{
Struct1(std::unique_ptr<std::string> pStr)
: pStr_(std::move(pStr)){}
~Struct1(){}
Struct1(Struct1& other)
: pStr_(std::move(other.pStr_)){}
std::unique_ptr<std::string> pStr_;
};
这是主要的。无论我尝试什么,我都会得到 insert
的“无匹配功能”
int main () {
std::string s("key");
std::unique_ptr<std::string> pStr = std::make_unique<std::string>("Hello");
std::map<std::string, Struct1>list;
Struct1 ste(std::move(pStr));
std::pair<std::string, Struct1> p(s,ste); // copy into a pair
// std::pair<std::string, Struct1> p(s,std::move(ste)); // copy into a pair
// auto p = std::make_pair(s, std::move(ste));
// auto p = std::make_pair(s, ste);
// list.insert(std::move(p));
list.insert(p);
Struct1(Struct1& other)
按照语言标准,它是复制构造函数;你在这里所做的(我不知道是拼写错误还是故意的)是 auto_ptr
风格的 neither-move-nor-copy-semantics。虽然完成后,复制分配是 auto-generated,而移动操作被完全删除(除非手动定义)。
你不想要那个吗?
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <memory>
struct Struct1
{
Struct1(std::unique_ptr<std::string> pStr)
: pStr_(std::move(pStr)){}
~Struct1(){}
Struct1(Struct1&& other) //double! ampersand
: pStr_(std::move(other.pStr_)){}
std::unique_ptr<std::string> pStr_;
};
int main () {
std::string s("key");
std::unique_ptr<std::string> pStr = std::make_unique<std::string>("Hello");
std::map<std::string, Struct1>list;
Struct1 ste(std::move(pStr));
std::pair<std::string, Struct1> p{s,std::move(ste)}; //note the move
list.insert(std::move(p)); //and here
}
当您选择加入 struct
s 时,除非确实需要,否则您可以避免创建自己的构造函数。相反,Struct1
可以简单地是:
struct Struct1
{
std::unique_ptr<std::string> pStr_;
};
所有 copy/move 构造函数和赋值运算符将尽可能自动生成。但是,由于结构中有一个 unique_ptr
,它没有复制构造函数或赋值运算符,因此不会为您生成这些,无论如何您都不需要它们。
现在剩下的就很简单了,只要你记得正确地调用你的对象 move
:
std::string s("key");
std::map<std::string, Struct1> list;
// prefer using `auto` when the type can already be deduced from `make_unique`
auto pStr = std::make_unique<std::string>("Hello");
// You must move `pStr` to construct `ste` since `pStr` is a `unique_ptr`.
// Also note you are using bracket `{}`, instead of parentheses `()` to create `Struct1`
Struct1 ste{std::move(pStr)};
// With C++20, parentheses is also allowed:
Struct1 ste(std::move(pStr));
// Similarly, you must move `ste` since it contents a `unique_ptr` in it
// Also note the type of the pair, the Key must be `const`
std::pair<const std::string, Struct1> p(s, std::move(ste));
// Once again, you must move `p` for the same reason
list.insert(std::move(p));
此外,还有两个步骤可以缩短:
std::string s("key");
std::map<std::string, Struct1> list;
// You can create `ste` directly without creating `pStr` first.
// This will also reduce the chance for accidentally using `pStr` again later.
Struct1 ste{std::make_unique<std::string>("Hello")};
// You can then simply emplace `ste` into `list`, or use the subscript operator`[]` without creating the `pair` first
list.emplace(s, std::move(ste));
// or
list[s] = std::move(ste);
您甚至可以更积极地减少代码:
std::string s("key");
std::map<std::string, Struct1> list;
list[s] = {std::make_unique<std::string>("Hello")};
// or since C++20
list.emplace(s, std::make_unique<std::string>("Hello"));
我在(编译时,gcc 17)在包含 unique_ptr 的 std::map 中插入对象时遇到问题。如果我使用常规指针,它会编译(如果我取出复制构造函数!)。 这是包含 unique_ptr 的结构。使用构造函数、复制构造函数等,到处都有 std::move 语义。有人以前见过这个问题吗?
#include <utility> // std::pair, std::make_pair
#include <string> // std::string
#include <iostream> // std::cout
#include <map>
#include <memory>
struct Struct1
{
Struct1(std::unique_ptr<std::string> pStr)
: pStr_(std::move(pStr)){}
~Struct1(){}
Struct1(Struct1& other)
: pStr_(std::move(other.pStr_)){}
std::unique_ptr<std::string> pStr_;
};
这是主要的。无论我尝试什么,我都会得到 insert
的“无匹配功能”int main () {
std::string s("key");
std::unique_ptr<std::string> pStr = std::make_unique<std::string>("Hello");
std::map<std::string, Struct1>list;
Struct1 ste(std::move(pStr));
std::pair<std::string, Struct1> p(s,ste); // copy into a pair
// std::pair<std::string, Struct1> p(s,std::move(ste)); // copy into a pair
// auto p = std::make_pair(s, std::move(ste));
// auto p = std::make_pair(s, ste);
// list.insert(std::move(p));
list.insert(p);
Struct1(Struct1& other)
按照语言标准,它是复制构造函数;你在这里所做的(我不知道是拼写错误还是故意的)是 auto_ptr
风格的 neither-move-nor-copy-semantics。虽然完成后,复制分配是 auto-generated,而移动操作被完全删除(除非手动定义)。
你不想要那个吗?
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <memory>
struct Struct1
{
Struct1(std::unique_ptr<std::string> pStr)
: pStr_(std::move(pStr)){}
~Struct1(){}
Struct1(Struct1&& other) //double! ampersand
: pStr_(std::move(other.pStr_)){}
std::unique_ptr<std::string> pStr_;
};
int main () {
std::string s("key");
std::unique_ptr<std::string> pStr = std::make_unique<std::string>("Hello");
std::map<std::string, Struct1>list;
Struct1 ste(std::move(pStr));
std::pair<std::string, Struct1> p{s,std::move(ste)}; //note the move
list.insert(std::move(p)); //and here
}
当您选择加入 struct
s 时,除非确实需要,否则您可以避免创建自己的构造函数。相反,Struct1
可以简单地是:
struct Struct1
{
std::unique_ptr<std::string> pStr_;
};
所有 copy/move 构造函数和赋值运算符将尽可能自动生成。但是,由于结构中有一个 unique_ptr
,它没有复制构造函数或赋值运算符,因此不会为您生成这些,无论如何您都不需要它们。
现在剩下的就很简单了,只要你记得正确地调用你的对象 move
:
std::string s("key");
std::map<std::string, Struct1> list;
// prefer using `auto` when the type can already be deduced from `make_unique`
auto pStr = std::make_unique<std::string>("Hello");
// You must move `pStr` to construct `ste` since `pStr` is a `unique_ptr`.
// Also note you are using bracket `{}`, instead of parentheses `()` to create `Struct1`
Struct1 ste{std::move(pStr)};
// With C++20, parentheses is also allowed:
Struct1 ste(std::move(pStr));
// Similarly, you must move `ste` since it contents a `unique_ptr` in it
// Also note the type of the pair, the Key must be `const`
std::pair<const std::string, Struct1> p(s, std::move(ste));
// Once again, you must move `p` for the same reason
list.insert(std::move(p));
此外,还有两个步骤可以缩短:
std::string s("key");
std::map<std::string, Struct1> list;
// You can create `ste` directly without creating `pStr` first.
// This will also reduce the chance for accidentally using `pStr` again later.
Struct1 ste{std::make_unique<std::string>("Hello")};
// You can then simply emplace `ste` into `list`, or use the subscript operator`[]` without creating the `pair` first
list.emplace(s, std::move(ste));
// or
list[s] = std::move(ste);
您甚至可以更积极地减少代码:
std::string s("key");
std::map<std::string, Struct1> list;
list[s] = {std::make_unique<std::string>("Hello")};
// or since C++20
list.emplace(s, std::make_unique<std::string>("Hello"));