鱼C论坛

 找回密码
 立即注册
查看: 2817|回复: 11

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

[复制链接]
发表于 2014-4-3 22:20:38 | 显示全部楼层 |阅读模式
5鱼币
本帖最后由 吃肉的考拉 于 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[size];
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[size];
*data = *rhs.data; //两个指针,指向不同的地址,但里面的内容值是一样的
}
else
{
std::cout << "赋值号两边为同个对象,不做处理!\n";
}

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

最佳答案

查看完整内容

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

使用道具 举报

发表于 2014-4-3 22:20:39 | 显示全部楼层
本帖最后由 Arthkee 于 2014-4-4 11:23 编辑

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


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2014-4-3 23:09:49 | 显示全部楼层
自问自答吧,因为这个类里不只一个属性,=重载操作符里只对 指针data进行了操作,没有对size,sp等属性进行赋值。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2014-4-3 23:27:49 | 显示全部楼层
$[5~68`OP_B66}QA1A~_$NH.jpg 这好像还是错的 ,求解决
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2014-4-4 08:40:20 | 显示全部楼层
这个应该涉及到浅拷贝,具体可以看看C++的相关章节,我大概改了下,你可以看看,构造的时候多了类内变量初始化,以及拷贝的过程。
安全检测没有做,例如Push的时候比较下容量,删除的时候检查sp,拷贝的时候检查SP和size
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 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[size];
                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[m_Size];
                        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[m_sp++] = 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;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2014-4-4 09:12:55 | 显示全部楼层

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

这句编译通不过咧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2014-4-4 09:33:30 | 显示全部楼层
吃肉的考拉 发表于 2014-4-4 09:12
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[i]);                       
}我这么搞了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2014-4-4 11:12:14 | 显示全部楼层
吃肉的考拉 发表于 2014-4-4 09:12
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));
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2014-4-4 12:49:30 | 显示全部楼层
呵呵!楼上的技术很高以后还要向你多多学习呢!我在调试这个程序的时候,当程序运行到析构造器的时候,程序就发生异常了,反汇编过来的话,发现是程序是调用到这个函数的时候:00401CAC   call        operator delete (00409390)就发生异常了,最后我也困惑了,经过你的这番讲解之后原来是这样啊!
QQ截图20140404124424.jpg
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2014-4-4 14:53:33 | 显示全部楼层
本帖最后由 Arthkee 于 2014-4-4 14:54 编辑
青玄 发表于 2014-4-4 12:49
呵呵!楼上的技术很高以后还要向你多多学习呢!我在调试这个程序的时候,当程序运行到析构造器的时候,程序 ...

delete 崩溃的原因一般就是指针已经被释放掉了,或者赋值错误指针指向了一个不存在的地址(中间不正确的赋值,或者根本没初始化),可以在delete之前看看指针的数据是什么样的,从这两个方面出发,应该就能找到问题了。我记得早上看的时候应该是没初始化。{:1_1:}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2014-4-9 20:36:18 | 显示全部楼层
本帖最后由 吃肉的考拉 于 2014-4-9 20:37 编辑
Arthkee 发表于 2014-4-3 22:20
您这样写,是不行的,您看语义,r.data是什么意思,是一个型的数组,而Push呢是要把一个型元素Push进去。 ...

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

                        你的我也编译过了~
[/i]
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-25 23:58

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表