如何从字符串向量构造对象并避免复制?
How to construct objects from a vector of string and avoid copying?
假设MyClass
有两个std::vector
类型的成员变量,一个是Data
类型的成员变量,另一个是StrData
(包含字符串)成员变量。我删除了默认和复制构造函数以防止编译器进行不必要的复制:
struct Data {
int x;
float y;
Data(int x, float y) : x(x), y(y) {}
Data() = delete;
Data(const Data& other) = delete;
};
struct StrData {
std::string xstr;
StrData(std::string x) : xstr(x){}
StrData() = delete;
StrData(const StrData& other) = delete;
};
class MyClass {
std::vector<Data> m_vect_data;
std::vector<StrData> m_vect_str_data;
public:
MyClass(const std::vector<Data> &m_vect_data,
const std::vector<StrData> &m_vect_str_data) : m_vect_data(
m_vect_data), m_vect_str_data(m_vect_str_data) {}
};
现在我正在尝试使用以下初始化列表构造我的 class:
MyClass s{{{1,2.0}, {2,4.0}}, {{"name"}}};
编译这段代码时,我得到了这样的抱怨:
/usr/include/c++/7/bits/stl_construct.h:75:7: error: use of deleted function ‘StrData::StrData(const StrData&)’
为什么编译器正确初始化了结构Data
仅包含整数类型(int 和 float)而不能初始化
第二个结构,即 StrData
,不需要复制构造函数?
您可以移动而不是复制。
首先,您使用向量的 vector(std::initializer_list<T>, const Allocator&);
构造函数时出现问题。初始化列表只能被复制,因此对于不可复制的类型来说这是不行的。
另一种方法是首先将列表声明为数组,创建一系列移动迭代器,然后改用迭代器构造函数:
Data datas[] = {
{1,2.0},
{2,4.0},
};
StrData strs[] = {
{"name"},
};
MyClass s{
{std::make_move_iterator(std::begin(datas)), std::make_move_iterator(std::end(datas))},
{std::make_move_iterator(std::begin(strs)), std::make_move_iterator(std::end(strs))},
};
现在,这还行不通,因为您的构造函数从参数向量中复制。简单的解决方案是按值获取向量,并将它们移动到成员中:
MyClass(std::vector<Data> m_vect_data,
std::vector<StrData> m_vect_str_data
) : m_vect_data(std::move(m_vect_data)),
m_vect_str_data(std::move(m_vect_str_data))
{}
最后,你必须让你的 Data
和 StrData
类 可移动(它们不是隐含的,因为删除了复制构造函数)否则移动迭代器技巧不会'工作:
struct Data {
// ...
Data(Data&&);
};
struct StrData {
// ...
StrData(StrData&&);
};
PS.
使 类 不可复制仅作为查找意外副本的调试工具才有意义。特别是在 Data
的情况下,它的复制速度和移动速度一样快。
此外,在构造函数中接受向量是非常有限的。如果您可以使用模板,则可以改为使用采用成对迭代器的模板构造函数。
假设MyClass
有两个std::vector
类型的成员变量,一个是Data
类型的成员变量,另一个是StrData
(包含字符串)成员变量。我删除了默认和复制构造函数以防止编译器进行不必要的复制:
struct Data {
int x;
float y;
Data(int x, float y) : x(x), y(y) {}
Data() = delete;
Data(const Data& other) = delete;
};
struct StrData {
std::string xstr;
StrData(std::string x) : xstr(x){}
StrData() = delete;
StrData(const StrData& other) = delete;
};
class MyClass {
std::vector<Data> m_vect_data;
std::vector<StrData> m_vect_str_data;
public:
MyClass(const std::vector<Data> &m_vect_data,
const std::vector<StrData> &m_vect_str_data) : m_vect_data(
m_vect_data), m_vect_str_data(m_vect_str_data) {}
};
现在我正在尝试使用以下初始化列表构造我的 class:
MyClass s{{{1,2.0}, {2,4.0}}, {{"name"}}};
编译这段代码时,我得到了这样的抱怨:
/usr/include/c++/7/bits/stl_construct.h:75:7: error: use of deleted function ‘StrData::StrData(const StrData&)’
为什么编译器正确初始化了结构Data
仅包含整数类型(int 和 float)而不能初始化
第二个结构,即 StrData
,不需要复制构造函数?
您可以移动而不是复制。
首先,您使用向量的 vector(std::initializer_list<T>, const Allocator&);
构造函数时出现问题。初始化列表只能被复制,因此对于不可复制的类型来说这是不行的。
另一种方法是首先将列表声明为数组,创建一系列移动迭代器,然后改用迭代器构造函数:
Data datas[] = {
{1,2.0},
{2,4.0},
};
StrData strs[] = {
{"name"},
};
MyClass s{
{std::make_move_iterator(std::begin(datas)), std::make_move_iterator(std::end(datas))},
{std::make_move_iterator(std::begin(strs)), std::make_move_iterator(std::end(strs))},
};
现在,这还行不通,因为您的构造函数从参数向量中复制。简单的解决方案是按值获取向量,并将它们移动到成员中:
MyClass(std::vector<Data> m_vect_data,
std::vector<StrData> m_vect_str_data
) : m_vect_data(std::move(m_vect_data)),
m_vect_str_data(std::move(m_vect_str_data))
{}
最后,你必须让你的 Data
和 StrData
类 可移动(它们不是隐含的,因为删除了复制构造函数)否则移动迭代器技巧不会'工作:
struct Data {
// ...
Data(Data&&);
};
struct StrData {
// ...
StrData(StrData&&);
};
PS.
使 类 不可复制仅作为查找意外副本的调试工具才有意义。特别是在 Data
的情况下,它的复制速度和移动速度一样快。
此外,在构造函数中接受向量是非常有限的。如果您可以使用模板,则可以改为使用采用成对迭代器的模板构造函数。