我想创建一个具有不同类型A对象的矢量但是......
此代码抛出此异常: free():无效指针:0x0000000000401757 ***
#include <vector>
class A
{
char * elem;
public:
A()
{
elem = new char[10];
}
void setA(char* name)
{
elem = name;
}
~A()
{
delete[] elem;
}
};
int main(int argc, char **argv)
{
std::vector<A> v_a;
for (int i = 0; i < 10; ++i)
{
A m_a;
m_a.setA("jaja");
v_a.push_back(m_a);
}
}
为什么会这样?如何实施正确的解决方案?
答案 0 :(得分:2)
调用setA(...)
时,您没有复制字符串的数据,而是复制本地字符串的地址。 (查看cplusplus.com关于指针和字符串文字的内容)
在setA(...)
调用结束的块结束后,此字符串超出范围,因此之后地址无效
所以你试图从堆中分配的析构函数中的堆释放内存,并且此时已经很久了......
更新建议1:于2016年1月27日添加
在将A
的实例推送到std::vector
时,还需要考虑复制ctor的需要。遵守Rule of three我也添加了一个复制赋值运算符。
妥善处理可能'错误'大小的字符串
#include <cstring>
...
/// copy ctor
A(const A& other) :
elem(new char[10])
{
// prevent duplicate code
setA(other.elem);
}
/// copy assignment operator
A& operator=(const A& other)
{
// prevent duplicate code
setA(other.elem);
return *this;
}
/// set A's name (which is truncated to 9 characters if necessary)
void setA(const char* name)
{
// copy first 9 chars from name
// if there's fewer chars: elem is padded with zeros
std::strncpy(elem, name, 9);
// add null character / zero (string delimiter) manually
// this is necessary for cases where name has 10 or more chars
elem[9] = 0;
}
(已作废)建议1:继续使用c样式字符串
在setA(...)
的参数列表中添加一个长度指示器(这是可选的,您还可以计算出方法内部字符串的长度......)
#include <cstring>
...
void setA(char* name, size_t length)
{
std::memcpy(elem, name, length);
}
建议2:切换到c ++样式字符串
使用std::string
(我更喜欢这个版本,因为它可以节省内存处理并且非常直观地读取)
#include <string>
class A
{
std::string elem;
public:
A(){}
void setA(std::string name)
{
elem = name;
}
~A(){}
};
答案 1 :(得分:1)
修改elem
的值,该值是指向免费商店中分配的内存区域的指针。现在,elem
指向字符串文字,不适用于delete
或delete[]
。
不在免费商店中的delete
对象是未定义的行为。你的析构函数会尝试它。