鱼C论坛

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

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

[复制链接]
发表于 2014-4-3 22:20:38 | 显示全部楼层 |阅读模式
5鱼币
本帖最后由 吃肉的考拉 于 2014-4-9 20:29 编辑
  1. #include <iostream>
  2. #include <string>


  3. template <class T>//类模板
  4. class Stack
  5. {
  6. public:
  7. Stack(unsigned int size = 10)
  8. {
  9. std::cout << "进入主构造器\n";
  10. this->size = size;
  11. data = new T[size];
  12. sp = 0;
  13. flag = 1;
  14. std::cout << "离开主构造器\n";
  15. }
  16. Stack( const Stack &rhs)
  17. {
  18. std::cout << "进入副本构造器\n";
  19. flag =0;
  20. *this = rhs; //该=已经被重载
  21. std::cout << "离开副本构造器\n";
  22. }
  23. ~Stack()
  24. {
  25. std::cout << "进入析构造器\n";
  26. delete []data;
  27. std::cout << "离开析构造器\n";
  28. }
  29. Stack & operator = (const Stack &rhs)
  30. {
  31. std::cout << "进入赋值语句重载\n";

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

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

  47. std::cout <<"离开赋值语句重载\n";
  48. return *this;
  49. }
  50. void push(T value)
  51. {
  52. data[sp++] = value;
  53. }
  54. T pop()
  55. {
  56. return data[--sp];
  57. }

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

  63. };

  64. int main()
  65. {

  66. Stack<int> intStack(100);


  67. intStack.push(1);
  68. intStack.push(2);
  69. intStack.push(3);

  70. Stack<int> intStack1 = intStack;

  71. std::cout << intStack.pop() << std::endl;
  72. std::cout << intStack.pop() << std::endl;
  73. std::cout << intStack.pop() << std::endl;


  74. intStack1.push(1);
  75. intStack1.push(2);
  76. intStack1.push(3);

  77. std::cout << intStack1.pop() << std::endl;
  78. std::cout << intStack1.pop() << std::endl;
  79. std::cout << intStack1.pop() << std::endl;

  80. return 0;
  81. }
复制代码

最佳答案

查看完整内容

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


小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

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

使用道具 举报

 楼主| 发表于 2014-4-3 23:27:49 | 显示全部楼层
$[5~68`OP_B66}QA1A~_$NH.jpg 这好像还是错的 ,求解决
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

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

使用道具 举报

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

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

这句编译通不过咧
小甲鱼最新课程 -> https://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]);                       
}我这么搞了
小甲鱼最新课程 -> https://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));
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

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

使用道具 举报

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

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

使用道具 举报

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

[i]

  1. for(int i = 0; i < rhs.sp; i++)
  2. {
  3. push(rhs.data[i]);
  4. }
复制代码


                        你的我也编译过了~
[/i]
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-4-21 05:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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