使用复制构造函数后双重释放子对象
Double free of child object after using the copy constructor
我无法弄清楚为什么(看起来)一个对象被破坏了两次。
如果我创建一个 class (B) 的对象,其中包含另一个 class (A) 的对象,然后我复制该对象。复制的对象被破坏两次。虽然它看起来像这样。我无法弄清楚这个输出。
我创建了以下(至少?)示例,它似乎触发了我的问题:
#include <stdio.h>
#include <stdint.h>
template <class T>
class A
{
public:
A()
{
myCtr = ++ctr;
printf("class A default Constructor - object id: %u\n", myCtr);
}
A(const A<T> &a2) {
myCtr = ++ctr;
printf("class A copy constructor - object id: %u\n", myCtr);
}
~A()
{
printf("class A destructor - object id: %u\n", myCtr);
}
void add(T item) {
/* Irrelevant */
}
private:
uint64_t myCtr;
static uint64_t ctr;
};
class B
{
public:
B() {
}
B(char * input, uint32_t len) {
for (uint32_t i = 0; i < len; i++)
{
characters.add(input[i]);
}
}
B(const B &b2) {
characters = A<char>(b2.characters);
}
~B() {
}
private:
A<char> characters;
};
template <class T>
uint64_t A<T>::ctr = 0;
int main(int argc, char *argv[]) {
B b1 = B((char *)"b1", 2);
B b2 = B(b1);
return 0;
}
这会产生以下输出:
class A default Constructor - object id: 1
class A default Constructor - object id: 2
class A copy constructor - object id: 3
class A destructor - object id: 3
class A destructor - object id: 3
class A destructor - object id: 1
对象 id 3 被破坏了两次,而对象 id 2 根本没有被破坏。
我正在使用以下编译器:
Microsoft (R) C/C++ 优化编译器版本 19.14.26429.4
万一你投反对票。请说明原因。我很乐意尝试改进我的问题。
您需要关注rule of 5。如果你实现了一个非平凡的析构函数,copy/move assign/construct,你必须实现所有 5 个,或者给出一个很好的理由,或者删除它们。
您实现了销毁和复制构造函数。你忽略了其他 3 个。添加它们。
此外 characters = A<char>(b2.characters);
您的复制 ctor 调用复制分配。你不跟踪的,这就是你的计数关闭的原因。您在柜台分配。
混乱来自这一行。
characters = A<char>(b2.characters);
一个默认生成的赋值运算符将对象3复制到对象2,包括myCtr
.
myCtr
不是 const
,因此它可能会在其生命周期内发生变化。如果您需要一个值保持不变,请将其设置为 const
.
这是您的 class 的一个版本,它将按您期望的方式运行。
template <class T>
class A
{
public:
A()
: myCtr( ++ctr )
{
printf("class A default Constructor - object id: %u\n", myCtr);
}
A(const A<T> &a2)
: myCtr( ++ctr )
{
printf("class A copy constructor - object id: %u\n", myCtr);
}
A<T>& operator=(const A<T> &a2) {
// Copy what's needed from a2 here.
return *this;
}
~A()
{
printf("class A destructor - object id: %u\n", myCtr);
}
void add(T item) {
/* Irrelevant */
}
private:
const uint64_t myCtr;
static uint64_t ctr;
};
我无法弄清楚为什么(看起来)一个对象被破坏了两次。
如果我创建一个 class (B) 的对象,其中包含另一个 class (A) 的对象,然后我复制该对象。复制的对象被破坏两次。虽然它看起来像这样。我无法弄清楚这个输出。
我创建了以下(至少?)示例,它似乎触发了我的问题:
#include <stdio.h>
#include <stdint.h>
template <class T>
class A
{
public:
A()
{
myCtr = ++ctr;
printf("class A default Constructor - object id: %u\n", myCtr);
}
A(const A<T> &a2) {
myCtr = ++ctr;
printf("class A copy constructor - object id: %u\n", myCtr);
}
~A()
{
printf("class A destructor - object id: %u\n", myCtr);
}
void add(T item) {
/* Irrelevant */
}
private:
uint64_t myCtr;
static uint64_t ctr;
};
class B
{
public:
B() {
}
B(char * input, uint32_t len) {
for (uint32_t i = 0; i < len; i++)
{
characters.add(input[i]);
}
}
B(const B &b2) {
characters = A<char>(b2.characters);
}
~B() {
}
private:
A<char> characters;
};
template <class T>
uint64_t A<T>::ctr = 0;
int main(int argc, char *argv[]) {
B b1 = B((char *)"b1", 2);
B b2 = B(b1);
return 0;
}
这会产生以下输出:
class A default Constructor - object id: 1
class A default Constructor - object id: 2
class A copy constructor - object id: 3
class A destructor - object id: 3
class A destructor - object id: 3
class A destructor - object id: 1
对象 id 3 被破坏了两次,而对象 id 2 根本没有被破坏。
我正在使用以下编译器: Microsoft (R) C/C++ 优化编译器版本 19.14.26429.4
万一你投反对票。请说明原因。我很乐意尝试改进我的问题。
您需要关注rule of 5。如果你实现了一个非平凡的析构函数,copy/move assign/construct,你必须实现所有 5 个,或者给出一个很好的理由,或者删除它们。
您实现了销毁和复制构造函数。你忽略了其他 3 个。添加它们。
此外 characters = A<char>(b2.characters);
您的复制 ctor 调用复制分配。你不跟踪的,这就是你的计数关闭的原因。您在柜台分配。
混乱来自这一行。
characters = A<char>(b2.characters);
一个默认生成的赋值运算符将对象3复制到对象2,包括myCtr
.
myCtr
不是 const
,因此它可能会在其生命周期内发生变化。如果您需要一个值保持不变,请将其设置为 const
.
这是您的 class 的一个版本,它将按您期望的方式运行。
template <class T>
class A
{
public:
A()
: myCtr( ++ctr )
{
printf("class A default Constructor - object id: %u\n", myCtr);
}
A(const A<T> &a2)
: myCtr( ++ctr )
{
printf("class A copy constructor - object id: %u\n", myCtr);
}
A<T>& operator=(const A<T> &a2) {
// Copy what's needed from a2 here.
return *this;
}
~A()
{
printf("class A destructor - object id: %u\n", myCtr);
}
void add(T item) {
/* Irrelevant */
}
private:
const uint64_t myCtr;
static uint64_t ctr;
};