自定义容器适用于 g++(Rstudio),不适用于 MSVS 2012
Customized container works fine with g++(Rstudio), not fine with MSVS 2012
我有一段 C++ 测试代码在 Rstudio 中运行良好,它使用 g++,但在 MSVS 2012 中会导致 运行 次错误:
template<typename T>
struct vec{
T*head, *tail;
vec()
{
head=NULL;
tail=NULL;
}
vec(int n)
{
head=(T*)malloc(sizeof(T)*n);
tail=head+n;
}
T operator [] (int i) const {return *(head+i);}
T & operator [] (int i) {return *(head+i);}
~vec(){free(head);}
};
int main(){
std::vector<int>y(3);
y[0]=1; y[1]=2; y[2]=3;
vec<int>x1(3);
x1[0]=y[0];
std::cout<<"vec of integers, [] overloading works fine \n";
std::vector<std::vector<int>::iterator>z(3);
z[0]=y.begin();
z[1]=y.begin()+1;
z[2]=y.begin()+2;
vec<std::vector<int>::iterator>x2(3);
x2[0]=z[0];
std::cout<<*x2[0]<<"\n";
std::cout<<"vec of std::vector::iterator, [] overloading g++ works fine, MSVS doesn't \n";
return 1;
}
代码显示如果vec包含整数,MSVS和Rstudio都可以正常工作;如果 vec 包含迭代器,MSVS 将 运行 出现以下错误:
我感觉到它与迭代器有关。谁能让我知道我的错误在哪里?顺便说一句,我只在 MSVS 中包含了矢量头文件。
谢谢!
VS 在调试模式下的迭代器中内置了额外的错误检查。它在您的代码中发现了一个合法的错误!错误是您将未初始化的内存重新解释为已初始化的对象:
vec(int n){head=(T*)malloc(sizeof(T)*n);tail=head+n;}
^^^^^^^^^^^^^^^^^^^^^^^
T & operator [] (int i) {return *(head+i);}
^^^^^^^^^
x2[0]=z[0];
^^^^^^
赋值在矢量迭代器对象上调用 operator=
,它实际上是未初始化的内存,当它试图将部分内存解释为有效数据时会导致您看到的崩溃。 (顺便说一句,0xCDCDCDCD 是调试器通常用来填充未初始化内存的内容,以帮助更快地捕获此类错误。)
我建议使用 new
/delete
而不是 malloc。在 C++ 中很难正确分配原始内存(普通内存管理已经够难了)。
另请注意,在一般情况下,malloc
可能不会为所有对象类型生成具有足够高对齐度的块(尽管大多数情况下会这样,因为很少有对象对齐到超过 16 个字节).
您正在使用 malloc
分配(未初始化的)内存,并试图将其解释为像迭代器那样的非 POD 类型。这注定会失败 - operator=
一个对象需要一个初始化的对象作为它的左操作数,但是你给它一个垃圾值(因此崩溃)。
此外,您没有调用元素的析构函数,因为您使用的是普通 free
。
一个简单的解决方案是在构造函数中使用 new T[n]
而不是 malloc
(在析构函数中使用 delete[]
)。这要求您的 T
是可默认构造的;有一些方法可以削弱这个要求(包括放置 new
和一些保证对齐的技巧)。
顺便说一句,你的 vec
class 既没有实现 "rule of three" 也没有实现 "rule of five",既没有禁用复制构造,所以你将有双如果您的 vec 对象被复制,则释放。
我有一段 C++ 测试代码在 Rstudio 中运行良好,它使用 g++,但在 MSVS 2012 中会导致 运行 次错误:
template<typename T>
struct vec{
T*head, *tail;
vec()
{
head=NULL;
tail=NULL;
}
vec(int n)
{
head=(T*)malloc(sizeof(T)*n);
tail=head+n;
}
T operator [] (int i) const {return *(head+i);}
T & operator [] (int i) {return *(head+i);}
~vec(){free(head);}
};
int main(){
std::vector<int>y(3);
y[0]=1; y[1]=2; y[2]=3;
vec<int>x1(3);
x1[0]=y[0];
std::cout<<"vec of integers, [] overloading works fine \n";
std::vector<std::vector<int>::iterator>z(3);
z[0]=y.begin();
z[1]=y.begin()+1;
z[2]=y.begin()+2;
vec<std::vector<int>::iterator>x2(3);
x2[0]=z[0];
std::cout<<*x2[0]<<"\n";
std::cout<<"vec of std::vector::iterator, [] overloading g++ works fine, MSVS doesn't \n";
return 1;
}
代码显示如果vec包含整数,MSVS和Rstudio都可以正常工作;如果 vec 包含迭代器,MSVS 将 运行 出现以下错误:
我感觉到它与迭代器有关。谁能让我知道我的错误在哪里?顺便说一句,我只在 MSVS 中包含了矢量头文件。
谢谢!
VS 在调试模式下的迭代器中内置了额外的错误检查。它在您的代码中发现了一个合法的错误!错误是您将未初始化的内存重新解释为已初始化的对象:
vec(int n){head=(T*)malloc(sizeof(T)*n);tail=head+n;}
^^^^^^^^^^^^^^^^^^^^^^^
T & operator [] (int i) {return *(head+i);}
^^^^^^^^^
x2[0]=z[0];
^^^^^^
赋值在矢量迭代器对象上调用 operator=
,它实际上是未初始化的内存,当它试图将部分内存解释为有效数据时会导致您看到的崩溃。 (顺便说一句,0xCDCDCDCD 是调试器通常用来填充未初始化内存的内容,以帮助更快地捕获此类错误。)
我建议使用 new
/delete
而不是 malloc。在 C++ 中很难正确分配原始内存(普通内存管理已经够难了)。
另请注意,在一般情况下,malloc
可能不会为所有对象类型生成具有足够高对齐度的块(尽管大多数情况下会这样,因为很少有对象对齐到超过 16 个字节).
您正在使用 malloc
分配(未初始化的)内存,并试图将其解释为像迭代器那样的非 POD 类型。这注定会失败 - operator=
一个对象需要一个初始化的对象作为它的左操作数,但是你给它一个垃圾值(因此崩溃)。
此外,您没有调用元素的析构函数,因为您使用的是普通 free
。
一个简单的解决方案是在构造函数中使用 new T[n]
而不是 malloc
(在析构函数中使用 delete[]
)。这要求您的 T
是可默认构造的;有一些方法可以削弱这个要求(包括放置 new
和一些保证对齐的技巧)。
顺便说一句,你的 vec
class 既没有实现 "rule of three" 也没有实现 "rule of five",既没有禁用复制构造,所以你将有双如果您的 vec 对象被复制,则释放。