使用初始化列表初始化父类的指针

Posted

技术标签:

【中文标题】使用初始化列表初始化父类的指针【英文标题】:Initializing parent class' pointer using initializer list 【发布时间】:2021-08-08 00:21:08 【问题描述】:

我有一个类字符串:

    class strings
    
    protected:
    string *ptr;
    int size;
public:
    strings() 
        ptr = NULL;
        size = -1;
    
    strings(int size) 
        this->size = size;
        ptr = new string[size];
    
    string* retPtr() 
        return ptr;
    
    void setPtr(int size)
    
        ptr = new string[size];
        this->size = size;
    
    strings(const strings& obj) 
        this->size = obj.size;
        for (int i = 0;i < size;++i)
            this->ptr[i] = obj.ptr[i];
    
    friend istream& operator>>(istream& input, strings& obj) 
        cin.ignore();
        cout << "Enter " << obj.size << " string one by one:\n";
        for (int i = 0;i < obj.size;++i)
        
            getline(input, obj.ptr[i]);
        
        return input;
    
    friend ostream& operator<<(ostream& output, const strings& obj) 
        cout << "Strings are:\n";
        for (int i = 0;i < obj.size;++i)
            output << obj.ptr[i] << "\n";
        return output;
    
    void operator =(const strings& obj)
    
        this->size = obj.size;
        for (int i = 0;i < size;++i)
            ptr[i] = obj.ptr[i];
    
    ~strings()
    
        delete[]ptr;
    
;

另一个类stringsFromNumbers:

class stringsFromNumbers:public strings

    int numbers;
public:
    stringsFromNumbers()
        numbers = -1;
    
    stringsFromNumbers(int size, int numbers):strings(size)
        this->numbers = numbers;
    
    stringsFromNumbers(const stringsFromNumbers& obj)
    
        this->numbers = obj.numbers;
        this->size = obj.size;
        for (int i = 0;i < size;++i)
            this->ptr[i] = obj.ptr[i];
    
    friend istream& operator>>(istream& input, stringsFromNumbers& obj) 
        cin.ignore();
        cout << "Enter " << obj.size << " string one by one:\n";
        for (int i = 0;i < obj.size;++i)
        
            getline(cin, obj.ptr[i]);
        
        return input;
    
    friend ostream& operator<<(ostream& output, const stringsFromNumbers& obj) 
        cout << "Numbers are: " << obj.numbers;
        cout << "\nStrings are:\n";
        for (int i = 0;i < obj.size;++i)
            output << obj.ptr[i] << "\n";
        return output;
    
    void operator =(const stringsFromNumbers& obj)
    
        this->numbers = obj.numbers;
        this->size = obj.size;
        for (int i = 0;i < size;++i)
            this->ptr[i] = obj.ptr[i];
    
    ~stringsFromNumbers()
    
        delete[] ptr;
    
;

每当我尝试执行这行代码时:

stringsFromNumbers obj2(N, P);

其中 N 和 P 是有效整数,我收到“访问读取冲突”,您是否发现代码中有问题? 我已经坚持了将近2个小时。我已经尝试调试和修复它,我还尝试了多种其他方法。异常将我带到这个函数:

inline void _Container_base12::_Orphan_all() noexcept 
#if _ITERATOR_DEBUG_LEVEL == 2
    if (_Myproxy)  // proxy allocated, drain it
        _Lockit _Lock(_LOCK_DEBUG);

        for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) 
            (*_Pnext)->_Myproxy = nullptr;
        

        _Myproxy->_Myfirstiter = nullptr;
    
#endif // _ITERATOR_DEBUG_LEVEL == 2

这个问题很可能出在这个功能上,但是如何解决呢?

stringsFromNumbers(int size, int numbers):strings(size)
    this->numbers = numbers;

【问题讨论】:

两个类的复制构造函数和赋值运算符都损坏了。这可能是造成问题的原因。 我该如何解决?你说它坏了是什么意思? 无关:istream&amp; operator&gt;&gt;(istream&amp; input, stringsFromNumbers&amp; obj) 中的 cin.ignore(); 会让您后悔的。迟早你会发现自己在使用&gt;&gt; 而不会在需要ignoreing 的流中产生垃圾,并且你会丢弃你不想丢弃的数据。永远不要在 IO 事务之前丢弃数据。而是在流中留下垃圾的 IO 操作之后丢弃。 感谢您的指导,但这并不能解决我面临的问题?你能帮忙吗? 建议:备份您的代码并将其破解为minimal reproducible example。通常,您不必完成 MRE 的制作,因为在制作过程中进行了一些分而治之的过程,您将减少 bug 周围的噪音,足以发现并修复 bug。如果您在 MRE 流程结束时仍未找到答案,请编辑问题并添加 MRE。 【参考方案1】:

stringsFromNumbers::~stringsFromNumbersstrings::strings 都在ptr 上调用delete[],因此尝试释放数组两次;第二次出现问题。

这些类中只有一个应该负责管理ptr 的生命周期。从stringsFromNumbers::~stringsFromNumbers 中删除delete[]

如果在其他情况下您有正当理由在子类的析构函数中释放数组,请确保父类析构函数能够处理新状态(例如,通过将 ptr 设置为 @987654329 @ 删除后),但一般情况下,您应该避免让两个类共同负责释放内存的复杂性。

【讨论】:

非常感谢您帮助我解决这个问题,我没有注意到这可能是个问题。解决了我的问题,谢谢。

以上是关于使用初始化列表初始化父类的指针的主要内容,如果未能解决你的问题,请参考以下文章

扩展1

C++11 必须使用初始化列表的场合

C++中,继承时,创建子类对象,能否在子类构造函数初始化列表里调用基类构造函数?

C++必须使用初始化列表初始化数据成员的三种情况

面向对象程序设计-C++_课时16子类父类关系

继承中的构造析构函数调用顺序