我在VS2013和C ++ 11中工作。
我正在实现一个自定义的模板化集合。当集合超出容量时,它会调整存储大小。此时,数据应从旧存储移动到新存储。
我真的想在数据元素T上强制执行安全移动语义。如果数据元素拥有资源,则应从原始存储中窃取资源的所有权并移至新存储。典型情况可能是数据库或其他资源的字符串或指针。
我有几种具有显式移动构造函数和移动赋值运算符的数据类型。但是如果具有显式移动构造函数(DeepData1)的那些类型本身是具有普通构造函数(DeepData2)的其他数据结构,则会出现错误。根据我阅读本文的方式,我希望我应该在DeepData2上获得一个隐式编译器生成的移动构造函数。 http://en.cppreference.com/w/cpp/language/move_constructor
但是在下面的示例中,我展示了由于指针_IMPORTANT_DATA上的双重删除,依赖于DeepData2的隐式构造函数崩溃。如果我使DeepData2的移动构造函数显式,则代码运行正常。
我原本希望不需要这样做,并且能够依赖隐式移动构造函数。否则,用户代码似乎需要记住提供额外的构造函数和赋值。如果要求DeepData2肯定需要一个明确的移动构造函数,如果用户代码忘记提供一个构造函数,我是否可以将其作为错误?无论如何检测模板类型是否需要显式移动构造函数,因为具有显式移动构造函数的成员?当我使用std类型特征时,他们似乎没有给我足够的信息来写一个像“嘿用户代码,像模板arg T你需要移动语义而忘记”的体面断言
这很复杂。感谢您的任何建议或帮助
#include "stdafx.h"
#include <vector>
#include <algorithm>
#include <iostream>
template <typename T>
class DeepVector
{
public:
DeepVector()
{
deepCopyResize(4);
}
void push_back(T& v)
{
if (_capacity <= _count)
{
deepCopyResize(_capacity * 2);
}
// !! deep copy desired here !!
_data[_count++] = std::move(v);
}
T& operator[](int i) { return _data[i]; }
void deepCopyResize(int cap)
{
int n = std::min(_count, cap);
T* d = new T[cap];
if (_data)
{
for (int i = 0; i < n; ++i)
{
// !! deep copy desired here !!
d[i] = std::move(_data[i]);
}
delete[] _data;
}
_data = d;
_capacity = cap;
_count = n;
}
private:
int _capacity = 0;
int _count = 0;
T* _data = nullptr;
};
struct FlatData1
{
int x = 0, y = 0;
};
struct DeepData1
{
DeepData1()
{
}
DeepData1(int s)
{
_size = s;
_IMPORTANT_DATA = new int[_size];
}
// move constructor
DeepData1(DeepData1&& rhs)
{
_size = rhs._size;
_IMPORTANT_DATA = rhs._IMPORTANT_DATA; // pilfer
rhs._size = 0;
rhs._IMPORTANT_DATA = nullptr;
}
// move operator
DeepData1& operator=(DeepData1&& rhs)
{
_size = rhs._size;
_IMPORTANT_DATA = rhs._IMPORTANT_DATA; // pilfer
rhs._size = 0;
rhs._IMPORTANT_DATA = nullptr;
return *this;
}
~DeepData1()
{
if (_IMPORTANT_DATA)
{
std::cout << "non-trivial destructor" << std::endl;
_size = 0;
// it is an error to delete important twice
delete[] _IMPORTANT_DATA;
_IMPORTANT_DATA = NULL;
}
}
int _size = 0;
int* _IMPORTANT_DATA = nullptr;
void resize(int s)
{
delete[] _IMPORTANT_DATA;
_IMPORTANT_DATA = new int[s];
_size = s;
}
};
struct DeepData2
{
int z = 0;
DeepData1 problem; // this data does not deep copy implicitly ?
// DeepData2() {}
// despite C++ standard forcing default not supported by VS2013
// DeepData2(DeepData2&&) = default;
// DeepData2(int s) : problem(s) {}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// where are my implicit move constructors?
// I have to uncomment these for the
// DeepData::operator=(DeepData&& rhs)
// operator to be called
/*
// have to manually implement move constructor?
DeepData2(DeepData2&& rhs)
{
z = std::move(rhs.z);
problem = std::move(rhs.problem);
}
// move operator
DeepData2& operator=(DeepData2&& rhs)
{
z = std::move(rhs.z);
problem = std::move(rhs.problem);
return *this;
}
*/
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
};
int _tmain(int argc, _TCHAR* argv[])
{
// ----------------------------------------------
DeepVector<int> v1;
for (int i=0; i<5; ++i)
{
v1.push_back(i);
}
if (v1[4] == 4)
{
std::cout << "resize 1 worked" << std::endl;
}
// ----------------------------------------------
DeepVector<FlatData1> v2;
for (int i = 0; i < 5; ++i)
{
v2.push_back(FlatData1());
v2[i].x = i;
v2[i].y = i;
}
if (v2[4].x == 4)
{
std::cout << "resize 2 worked" << std::endl;
}
// ----------------------------------------------
DeepVector<DeepData1> v3;
for (int i = 0; i < 5; ++i)
{
v3.push_back(DeepData1(10));
}
if (v3[4]._size == 10)
{
std::cout << "resize 3 worked" << std::endl;
}
// ----------------------------------------------
bool b1 = std::is_move_constructible<DeepData1>();
bool b2 = std::is_move_assignable<DeepData1>();
bool b3 = std::is_trivially_move_assignable<DeepData1>();
bool b4 = std::is_trivially_move_constructible<DeepData1>();
bool b5 = std::is_move_constructible<DeepData2>();
bool b6 = std::is_move_assignable<DeepData2>();
// VS2013 says DeepData2 is trivially moveable with the implicit constructors
bool b7 = std::is_trivially_move_assignable<DeepData2>();
bool b8 = std::is_trivially_move_constructible<DeepData2>();
DeepVector<DeepData2> v4;
for (int i = 0; i < 5; ++i)
{
DeepData2 d2;
d2.problem.resize(10);
v4.push_back(d2);
}
if (v4[4].problem._size == 10)
{
std::cout << "resize 4 worked" << std::endl;
}
return 0;
}
答案 0 :(得分:2)
MSVC2013不支持生成的或=default
移动构造函数(或赋值运算符)。
MSVC2015可以。它的主要缺失部分是实际的C ++ 11编译器,他们称之为&#34;表达SFINAE&#34;故障。
在不更换编译器的情况下,在MSVC2013和C ++ 11中工作是不可能的。您可以使用C ++ 03和它支持的C ++ 11部分进行混合编程。