C++中的双自由错误

Double-free error in C++

本文关键字:自由 错误 C++      更新时间:2023-10-16

我是C++的新手。我确实试图在我得到的书上找到答案,并在谷歌上搜索,但找不到问题根源的线索。

这可能真的很愚蠢。希望有人能照亮这里我在下面复制所有内容:

Hand::ShowHand2仅适用于"myHand.Add(pCard2)"不知怎么的,当我使用myHand.Add(pCard1)时,我得到了以下错误:

*** glibc detected *** /home/remy/workspace-C/myPoker/Debug/myPoker: double free or corruption (out): 0x00007fff7723d2d0 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7fef4fd1bb96]
/home/remy/workspace-C/myPoker/Debug/myPoker[0x401869]
/home/remy/workspace-C/myPoker/Debug/myPoker[0x40172c]
/home/remy/workspace-C/myPoker/Debug/myPoker[0x401b41]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7fef4fcbe76d]
/home/remy/workspace-C/myPoker/Debug/myPoker[0x400e19]
======= Memory map: ========
00400000-00404000 r-xp 00000000 07:00 875533                             /home/remy/workspace-C/myPoker/Debug/myPoker
00603000-00604000 r--p 00003000 07:00 875533                             /home/remy/workspace-C/myPoker/Debug/myPoker
00604000-00605000 rw-p 00004000 07:00 875533                             /home/remy/workspace-C/myPoker/Debug/myPoker
02534000-02555000 rw-p 00000000 00:00 0                                  [heap]

这是完整的代码:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Card
{
public:
    enum rank {ace = 1, two, three, four, five, six , seven, eight, nine, ten, jack, queen, king};
    enum suit {club =1 , diamonds, hearts, spades};
    friend ostream& operator    <<  (ostream& os,  Card& aCard);
    Card(rank r = ace, suit s = spades);
    rank m_rank;
    suit m_suit;
};
Card::Card(rank r, suit s){
    m_rank =    r;
    m_suit  =   s;
}
ostream& operator<<(ostream& os,  Card& aCard)
{
    const string RANKS[] = {"0", "A", "2", "3", "4", "5", "6", "7", "8", "9",
                        "10", "J", "Q", "K"};
    const string SUITS[] = {"c", "d", "h", "s"};
    os << RANKS[aCard.m_rank] << SUITS[aCard.m_suit];
    return os;
}
class Hand
{
    public:
    Hand();
    virtual ~Hand();
void Add(Card* pCard);
void Clear();
void ShowHand();
void ShowHand2();
    protected:
    vector<Card*> m_Cards;
};
Hand::Hand(){
    cout    << "hand is created "   << endl;
    m_Cards.reserve(7);
}
Hand::~Hand()
{
    Clear();
}
void Hand::Add(Card* pCard)
{
    cout    <<  "*pCard: "  <<  *pCard  << " is @: "    <<  pCard   <<  endl;
    m_Cards.push_back(pCard);
}
void Hand::Clear(){
    vector<Card*>::iterator iter = m_Cards.begin();
    for (iter = m_Cards.begin(); iter != m_Cards.end(); ++iter)
    {
    delete *iter;
    *iter   =   0;
    }
    m_Cards.clear();
}

void Hand::ShowHand(){
        int k = 1;
        vector<Card*>::iterator iter = m_Cards.begin();
    for (iter = m_Cards.begin() ; iter != m_Cards.end(); ++iter, ++k)
    {
        cout    << "card no "   <<  k   << " is: ";
        cout    <<  **iter  << endl ;
    }
}

void Hand::ShowHand2(){
        vector<Card*>::iterator iter = m_Cards.begin();
        cout << "this hand has "    <<  m_Cards.size()  << " card(s)."<< endl;
        for (iter = m_Cards.begin(); iter != m_Cards.end(); ++iter)
{
    cout    << **iter   <<  endl;
}
}

int main(){
Card c1(static_cast<Card::rank>(11), static_cast<Card::suit>(0));
Card*   pCard1  =   &c1;
Card*   pCard2;
pCard2  =   new Card(static_cast<Card::rank>(12), static_cast<Card::suit>(0));
Hand myHand;
myHand.Add(pCard1);
//  myHand.Add(pCard2);
//  myHand.ShowHand();
myHand.ShowHand2();
cout    <<  "End of Program"    <<  endl;

return 0;
}

非常感谢!

pCard1添加到手上,它是指向将自动销毁的局部变量的指针。但是,您的~Hand()将在其分配的所有卡上调用delete。给你免费的双人间。

如果使用pCard2,则通过new分配了Card实例,因此负责对其调用delete

正如你在评论中看到的,你应该考虑使用智能指针来避免这样的问题。

编辑要更详细地解释您的主要问题:您使用指向由编译器自动管理的局部变量的指针。然而,当手本身被破坏时,你将它add()给拥有指向对象所有权的手,因为它将删除它。这基本上导致同一对象有两个所有者。

通过new生成实例,就没有负责销毁的所有者。然而,当你把它添加到手牌中时,手牌就会拥有它并将其删除。

让我们来看看这个:

enum suit {club =1 , diamonds, hearts, spades};

在这里,您声明club1diamonds2`hearts3spades4

那么你就有了这个阵列

const string SUITS[] = {"c", "d", "h", "s"};

使用suit进行索引。

但是,数组的索引以开始,这意味着对于spade,您的索引超出了数组的边界,并在SUITS[4]处使用"字符串"时进入未定义行为的区域。