吃肉的考拉 发表于 2014-4-3 22:20:38

类模板加副本构造器,进入析构器删除出错

本帖最后由 吃肉的考拉 于 2014-4-9 20:29 编辑

#include <iostream>
#include <string>


template <class T>//类模板
class Stack
{
public:
Stack(unsigned int size = 10)
{
std::cout << "进入主构造器\n";
this->size = size;
data = new T;
sp = 0;
flag = 1;
std::cout << "离开主构造器\n";
}
Stack( const Stack &rhs)
{
std::cout << "进入副本构造器\n";
flag =0;
*this = rhs; //该=已经被重载
std::cout << "离开副本构造器\n";
}
~Stack()
{
std::cout << "进入析构造器\n";
delete []data;
std::cout << "离开析构造器\n";
}
Stack & operator = (const Stack &rhs)
{
std::cout << "进入赋值语句重载\n";

if(this != &rhs)
{
std::cout << "是否删除的标志位值为: "<< flag << std::endl;
if(flag)
{
std::cout << "执行删除\n";
delete [] data;
}

data = new T;
*data = *rhs.data; //两个指针,指向不同的地址,但里面的内容值是一样的
}
else
{
std::cout << "赋值号两边为同个对象,不做处理!\n";
}

std::cout <<"离开赋值语句重载\n";
return *this;
}
void push(T value)
{
data = value;
}
T pop()
{
return data[--sp];
}

private:
unsigned int size;
unsigned int sp;
int flag ; //是否在重载=操作符时删除原来的ptr
T *data;

};

int main()
{

Stack<int> intStack(100);


intStack.push(1);
intStack.push(2);
intStack.push(3);

Stack<int> intStack1 = intStack;

std::cout << intStack.pop() << std::endl;
std::cout << intStack.pop() << std::endl;
std::cout << intStack.pop() << std::endl;


intStack1.push(1);
intStack1.push(2);
intStack1.push(3);

std::cout << intStack1.pop() << std::endl;
std::cout << intStack1.pop() << std::endl;
std::cout << intStack1.pop() << std::endl;

return 0;
}

Arthkee 发表于 2014-4-3 22:20:39

本帖最后由 Arthkee 于 2014-4-4 11:23 编辑

吃肉的考拉 发表于 2014-4-4 09:33 static/image/common/back.gif
for(int i = 0; i < rhs.sp;i++)
{
push(rhs.data);                        

您这样写,是不行的,您看语义,r.data是什么意思,是一个<T>型的数组,而Push呢是要把一个<T>型元素Push进去。
即便这样改完Push的时候rhs.data的指针也要更改(push(*(rhs.data+i)); )。
我的直接把栈数据Copy过来,这种对简单类型变量比较适用。
你的那种对类/struct类型变量能更好应对一点,中间多了个拷贝构造,效率能差异点(轮询过程可以封个函数,友好一点)。
是吧?看你具体需求了,希望对您有帮助。{:1_1:}


吃肉的考拉 发表于 2014-4-3 23:09:49

自问自答吧,因为这个类里不只一个属性,=重载操作符里只对 指针data进行了操作,没有对size,sp等属性进行赋值。

吃肉的考拉 发表于 2014-4-3 23:27:49

这好像还是错的 ,求解决

Arthkee 发表于 2014-4-4 08:40:20

这个应该涉及到浅拷贝,具体可以看看C++的相关章节,我大概改了下,你可以看看,构造的时候多了类内变量初始化,以及拷贝的过程。
安全检测没有做,例如Push的时候比较下容量,删除的时候检查sp,拷贝的时候检查SP和size

Arthkee 发表于 2014-4-4 08:40:51

#include <iostream>
#include <string>

template <class T>//类模板
class Stack
{
public:
        Stack()
        {
                m_Size = 0;
                m_sp = 0;
                m_flag = 1;
                m_data = NULL;
        }

        Stack(unsigned int size)
        {
                std::cout << "进入主构造器\n";
                this->m_Size = size;
                m_data = new T;
                m_sp = 0;
                m_flag = 1;
                std::cout << "离开主构造器\n";
        }
        Stack( const Stack &rhs)
        {
                std::cout << "进入副本构造器\n";
                m_Size = 0;
                m_sp = 0;
                m_flag = 1;
                m_data = NULL;

                *this = rhs; //该=已经被重载
                std::cout << "离开副本构造器\n";
        }
        ~Stack()
        {
                std::cout << "进入析构造器\n";
                delete []m_data;
                std::cout << "离开析构造器\n";
        }
        Stack & operator = (const Stack &rhs)
        {
                std::cout << "进入赋值语句重载\n";

                if(this != &rhs)
                {
                        std::cout << "是否删除的标志位值为: "<< m_flag << std::endl;
                        if(m_flag && m_data)
                        {
                                std::cout << "执行删除\n";
                                delete [] m_data;
                                m_data = NULL;
                        }
                       
                        //赋值语句
                        m_Size = rhs.m_Size;
                        m_sp = rhs.m_sp;

                        m_data = new T;
                        memcpy_s(m_data, m_Size * sizeof(T), rhs.m_data, m_sp * sizeof(T));

                        //*data = *rhs.data; //两个指针,指向不同的地址,但里面的内容值是一样的
                }
                else
                {
                        std::cout << "赋值号两边为同个对象,不做处理!\n";
                }

                std::cout <<"离开赋值语句重载\n";
                return *this;
        }
        void push(T value)
        {
                m_data = value;
        }
        T pop()
        {
                return m_data[--m_sp];
        }

private:
        unsigned int m_Size;
        unsigned int m_sp;
        int m_flag ; //是否在重载=操作符时删除原来的ptr
        T* m_data;
};

int main()
{

        Stack<int> intStack(100);


        intStack.push(1);
        intStack.push(2);
        intStack.push(3);

        Stack<int> intStack1 = intStack;

        std::cout << intStack.pop() << std::endl;
        std::cout << intStack.pop() << std::endl;
        std::cout << intStack.pop() << std::endl;


        intStack1.push(4);
        intStack1.push(5);
        intStack1.push(6);

        std::cout << intStack1.pop() << std::endl;
        std::cout << intStack1.pop() << std::endl;
        std::cout << intStack1.pop() << std::endl;

        return 0;
}

吃肉的考拉 发表于 2014-4-4 09:12:55

Arthkee 发表于 2014-4-4 08:40 static/image/common/back.gif
#include
#include



memcpy_s(m_data, m_Size * sizeof(T), rhs.m_data, m_sp * sizeof(T));

这句编译通不过咧

吃肉的考拉 发表于 2014-4-4 09:33:30

吃肉的考拉 发表于 2014-4-4 09:12 static/image/common/back.gif
memcpy_s(m_data, m_Size * sizeof(T), rhs.m_data, m_sp * sizeof(T));

这句编译通不过咧

for(int i = 0; i < rhs.sp;i++)
{
push(rhs.data);                       
}我这么搞了

Arthkee 发表于 2014-4-4 11:12:14

吃肉的考拉 发表于 2014-4-4 09:12 static/image/common/back.gif
memcpy_s(m_data, m_Size * sizeof(T), rhs.m_data, m_sp * sizeof(T));

这句编译通不过咧

这句是安全函数,可以改为memcpy(m_data, rhs.m_data, m_sp * sizeof(T));

青玄 发表于 2014-4-4 12:49:30

呵呵!楼上的技术很高以后还要向你多多学习呢!我在调试这个程序的时候,当程序运行到析构造器的时候,程序就发生异常了,反汇编过来的话,发现是程序是调用到这个函数的时候:00401CAC   call      operator delete (00409390)就发生异常了,最后我也困惑了,经过你的这番讲解之后原来是这样啊!

Arthkee 发表于 2014-4-4 14:53:33

本帖最后由 Arthkee 于 2014-4-4 14:54 编辑

青玄 发表于 2014-4-4 12:49 static/image/common/back.gif
呵呵!楼上的技术很高以后还要向你多多学习呢!我在调试这个程序的时候,当程序运行到析构造器的时候,程序 ...
delete 崩溃的原因一般就是指针已经被释放掉了,或者赋值错误指针指向了一个不存在的地址(中间不正确的赋值,或者根本没初始化),可以在delete之前看看指针的数据是什么样的,从这两个方面出发,应该就能找到问题了。我记得早上看的时候应该是没初始化。{:1_1:}

吃肉的考拉 发表于 2014-4-9 20:36:18

本帖最后由 吃肉的考拉 于 2014-4-9 20:37 编辑

Arthkee 发表于 2014-4-3 22:20 http://bbs.fishc.com/static/image/common/back.gif
您这样写,是不行的,您看语义,r.data是什么意思,是一个型的数组,而Push呢是要把一个型元素Push进去。 ...

for(int i = 0; i < rhs.sp; i++)
{
push(rhs.data);
}


                        你的我也编译过了~
页: [1]
查看完整版本: 类模板加副本构造器,进入析构器删除出错