C ++中的双重自由错误

时间:2013-06-22 18:34:41

标签: c++

我是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;
}

提前非常感谢!

2 个答案:

答案 0 :(得分:3)

您将pCard1添加到您的手中,这是指向将自动销毁的局部变量的指针。 但是,您的~Hand()会在已分配的所有卡片上调用delete。 你有双倍的自由。

如果您使用pCard2,则您通过Card分配了new个实例,因此负责在其上调用删除。

正如您在评论中所看到的,您应该考虑使用智能指针来避免此类问题。

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

通过new生成实例,没有所有者负责销毁。 但是,当你将它添加到手上时,手拥有它并将其删除。

答案 1 :(得分:1)

让我们来看看:

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

在此,您声明club1diamonds2`hearts3spades成为4

然后你有这个数组

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

您使用suit进行索引。

但是,数组以开始索引,这意味着对于spade,您可以索引数组的边界,并输入未定义行为的区域当您在SUITS[4]使用“字符串”时。