在使用矢量和字符串时使用double-free

  • 本文关键字:double-free 字符串 c++
  • 更新时间 :
  • 英文 :


我编写了以下函数和一个简单的类,同时试图了解使用向量的工作成本有多高

void gen_random(string & str, const int len) 
{
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
srand((unsigned int)time(NULL));
str.reserve(len);
for (int i = 0; i < len; ++i) 
{
str += alphanum[rand() % (sizeof(alphanum) - 1)];
}
}
class Person
{
public:
//CTOR with parameter
Person(u_int32_t Id)
{
std::cout << "33[1;32mPerson CTOR: " << Id << "33[0m" << std::endl;
m_Id = Id;
m_RandSid = new string;
gen_random(*m_RandSid, 10);
}

//CCTOR
Person(const Person & p)
{
std::cout << "33[1;31mPerson CCTOR: " << p.m_Id << "33[0m" << std::endl;
m_Id = p.m_Id;
m_RandSid = p.m_RandSid; //trigger string operator=()
}

//MCTOR
Person(Person&& p)
{
std::cout << "33[1;34mPerson MCTOR: " << p.m_Id << "33[0m" << std::endl;
m_Id = p.m_Id;
m_RandSid = p.m_RandSid;
p.m_RandSid = nullptr;
}
//DTOR
~Person()
{
std::cout << "33[1;33mPerson DTOR: "<<m_Id <<"33[0m"<< std::endl;
if (nullptr != m_RandSid)
{
delete m_RandSid;
}
}

u_int32_t m_Id;
string * m_RandSid;
};

和驱动程序:

int main()
{
int a;
vector<Person> v;
for (int i = 0; i < 2; ++i)
{
std::cout <<std::endl<< "inserting person #" << i << std::endl;
std::cout << "Vector size = " << v.size()<< " Vector capacity = " << v.capacity() << std ::endl;
v.emplace_back(i); 
std::cout << *v[i].m_RandSid << std::endl;
std::cout << "Vector size = " << v.size()<< " Vector capacity = " << v.capacity() << std ::endl;
}
std::cout<<std::endl<<"--------------------------------------------------------"<<std::endl;

return 0;
}

当我运行这个程序时,我会得到以下输出:

inserting person #0
Vector size = 0 Vector capacity = 0
Person CTOR: 0
07QoUmgEe6
Vector size = 1 Vector capacity = 1
inserting person #1
Vector size = 1 Vector capacity = 1
Person CTOR: 1
Person CCTOR: 0
Person DTOR: 0
07QoUmgEe6
Vector size = 2 Vector capacity = 2
--------------------------------------------------------
Person DTOR: 0
free(): double free detected in tcache 2
  1. 我不知道我还能在哪里表演另一个免费节目:\
  2. 另一个问题是字符串是按每次执行而不是按对象随机化的,如果每次执行都执行srand,为什么所有字符串看起来都一样

在复制和移动构造函数中,您只需复制原始指针,这会使2个指针指向同一内存,当两个对象都被破坏时,您会得到双重释放:

Person(const Person & p)
{
std::cout << "33[1;31mPerson CCTOR: " << p.m_Id << "33[0m" << std::endl;
m_Id = p.m_Id;
m_RandSid = p.m_RandSid; // now both pointers point to the same memory
}

目前尚不清楚为什么需要动态分配的字符串对象,您应该只按值存储对象,但如果确实需要,则应该使用智能指针(std::shared_ptrstd::unique_ptr取决于您需要的所有权(。这不仅会使您的问题消失,而且您不必手动提供复制和移动构造函数,编译器生成的构造函数就足够了。

请注意,您的类也缺少适当的复制和移动赋值运算符,尽管它没有在代码中公开,但它仍然违反了3/5/zero规则,以后您的代码可能会出现问题。

  1. 您的复制构造函数复制指针值,并且应该进行深度复制(分配一个新字符串(。在这样一个简单的设计中,我会避免使用new/free作为字符串
  2. 您可以用第二精度的时间初始化(实际上重置(rand-time((。你的应用程序可能在不到一秒钟的时间内完成,因此有类似的字符串。只初始化rand一次(如启动应用程序时(

最新更新