class 个对象的 C++ 向量和动态内存分配 - 第 2 部分
C++ vector of class objects and dynamic memory allocation - part 2
这是对我之前在此处发布的问题 () 的跟进。
为了这个例子,Someclass
是一个过于简化的 class。重要的是要知道这个 class 的对象存储在其他地方的向量中。
Buffer
是另一个 class,它具有三种类型的成员:常规变量 (NAME)、向量 (S) 和指向动态分配的内存块 (DATA) 的指针。
如果我注释 v.erase(v.begin()+1);
行,那么代码会编译并运行良好。 Bur erase
产生许多错误,例如“使用已删除的函数 Buffer& Buffer::operator=(const Buffer&)
”。
我想我了解问题,但不知道如何解决。你能修改我的例子让它工作吗?请注意,该示例过于简单,我需要保留这两个 classes 和向量的使用。
谢谢。
using namespace std;
#include <cstdlib>
#include <vector>
#include <string>
using namespace std;
class Someclass
{
public:
int I;
Someclass(int i) {I = i;};
private:
};
class Buffer
{
public:
vector <Someclass> S;
string NAME;
float *DATA;
Buffer(int length, string name) {DATA = (float*) calloc (length,sizeof(float)); NAME = name;};
Buffer(const Buffer &buffer) = delete;
Buffer(Buffer&& buffer) {
S = buffer.S;
NAME = buffer.NAME;
DATA = buffer.DATA;
buffer.DATA = nullptr;
}
~Buffer(){
S.clear();
if (DATA) free(DATA);
};
private:
};
int main(int argc, char** argv)
{
vector <Buffer> v;
for (int i =0; i<10; i++)
{
cout<<i<<endl;
v.push_back(Buffer(1000,"name"));
}
v.erase(v.begin()+1);
v.clear();
return 0;
}
这是因为一个简单的原因。当您擦除一个条目时,阵列需要移除该“气泡”(即空槽)并压缩阵列。这意味着它需要移动一些东西。所以在搬家的时候,他们的做法是这样的,
// Form the MSVC xutility.h file.
for (; _First != _Last; ++_Dest, (void) ++_First) {
*_Dest = _STD move(*_First);
}
如您所见,他们移动它的方式是移动各个条目。这意味着您调用对象 Buffer
的复制赋值/移动赋值运算符。但是您没有定义任何赋值运算符,而是定义了一个移动构造函数。这告诉编译器,
“嘿,这个 Buffer 对象只有一个移动构造函数。也许用户只是想通过移动另一个构造 class。所以它不能有任何其他赋值(复制和移动)”
所以现在编译器不会为您生成它们。这意味着您现在不能将另一个 Buffer
复制或移动到另一个(除非您移动构建它)。这就是错误的原因。
解决方案是添加一个移动赋值运算符。
Buffer& operator=(Buffer&& other)
{
S = std::move(other.S);
NAME = std::move(other.NAME);
DATA = other.DATA;
other.DATA = nullptr; // Make sure to set it to nullptr.
return *this;
}
这是对我之前在此处发布的问题 (
Someclass
是一个过于简化的 class。重要的是要知道这个 class 的对象存储在其他地方的向量中。
Buffer
是另一个 class,它具有三种类型的成员:常规变量 (NAME)、向量 (S) 和指向动态分配的内存块 (DATA) 的指针。
如果我注释 v.erase(v.begin()+1);
行,那么代码会编译并运行良好。 Bur erase
产生许多错误,例如“使用已删除的函数 Buffer& Buffer::operator=(const Buffer&)
”。
我想我了解问题,但不知道如何解决。你能修改我的例子让它工作吗?请注意,该示例过于简单,我需要保留这两个 classes 和向量的使用。
谢谢。
using namespace std;
#include <cstdlib>
#include <vector>
#include <string>
using namespace std;
class Someclass
{
public:
int I;
Someclass(int i) {I = i;};
private:
};
class Buffer
{
public:
vector <Someclass> S;
string NAME;
float *DATA;
Buffer(int length, string name) {DATA = (float*) calloc (length,sizeof(float)); NAME = name;};
Buffer(const Buffer &buffer) = delete;
Buffer(Buffer&& buffer) {
S = buffer.S;
NAME = buffer.NAME;
DATA = buffer.DATA;
buffer.DATA = nullptr;
}
~Buffer(){
S.clear();
if (DATA) free(DATA);
};
private:
};
int main(int argc, char** argv)
{
vector <Buffer> v;
for (int i =0; i<10; i++)
{
cout<<i<<endl;
v.push_back(Buffer(1000,"name"));
}
v.erase(v.begin()+1);
v.clear();
return 0;
}
这是因为一个简单的原因。当您擦除一个条目时,阵列需要移除该“气泡”(即空槽)并压缩阵列。这意味着它需要移动一些东西。所以在搬家的时候,他们的做法是这样的,
// Form the MSVC xutility.h file.
for (; _First != _Last; ++_Dest, (void) ++_First) {
*_Dest = _STD move(*_First);
}
如您所见,他们移动它的方式是移动各个条目。这意味着您调用对象 Buffer
的复制赋值/移动赋值运算符。但是您没有定义任何赋值运算符,而是定义了一个移动构造函数。这告诉编译器,
“嘿,这个 Buffer 对象只有一个移动构造函数。也许用户只是想通过移动另一个构造 class。所以它不能有任何其他赋值(复制和移动)”
所以现在编译器不会为您生成它们。这意味着您现在不能将另一个 Buffer
复制或移动到另一个(除非您移动构建它)。这就是错误的原因。
解决方案是添加一个移动赋值运算符。
Buffer& operator=(Buffer&& other)
{
S = std::move(other.S);
NAME = std::move(other.NAME);
DATA = other.DATA;
other.DATA = nullptr; // Make sure to set it to nullptr.
return *this;
}