C ++中的指针帮助

时间:2017-09-26 00:39:03

标签: c++ arrays pointers polymorphism

我是c ++的新手(有一个java背景),因此指针对我来说有点新鲜。我正在处理一个指针数组,其中每个索引指向堆上的对象,如下所示:

Deck::Deck()
{
seed = rand()%100; //this will be used in shuffle method
srand(seed); 
for(int i=0;i<deckSize;i+=3) //deckSize=12 in this case, p defined as CardTypes* p[deckSize]
{
    p[i]= new Infantry(); 
    p[i+1] = new Artillery();
    p[i+2] = new Cavalry();

}

} 所有这3个类都是CardTypes类的子类(它只是创建的,所以我可以将diff类型存储在数组中)。

class CardTypes
{
public:
virtual string getCard() = 0;
virtual ~CardTypes() {};
};
class Infantry: public CardTypes
{
const string name = "Infantry";
public:
string getCard(); //this simply returns "name" so that I can differentiate each object in the array by a data value
};
class Artillery:public CardTypes 
{
const string name= "Artillery";
public:
string getCard();
};
class Cavalry:public CardTypes
{
const string name = "Cavalry";
public:
string getCard();
};

虽然不是一个很好的方法,但是我已经创建了另一个指针数组(CardTypes * s [deckSize],它将p中的指针随机复制到s中(因此模仿了一副牌中的洗牌):

void Deck::shuffle() //this is the method that puts objects in s to be grabbed in draw()
{
int j = 0;
int k = 1;
int l = 2; //initial setup(index 0 will have Infantry, index 1 will have Artillery and index 3 will have Cavalry and this pattern continues throughout p)
int n = rand()%3 + 1; //gives random # between 1 and 3 1=infantry,2 = artillery,3 = cavalry
int i=0; //counter for loop
while(i<deckSize)
{
     n = rand()%3+1;
    if(n==1)
    {
        if(j>9) //means no more infantry cards as due to pattern of p 
        infantry cards stop after index 9
        {
            continue; //used to reset loop foranother iteration(will get random number,I know this is bad for time complexity)
        }
        else
        {
        s[i] = p[j]; //copy "Infantry" pointer to s
        j+=3;
        i++;
        }
    }
    else if(n==2)
    {
        if(k>10)//means no Artillery cards due to pattern in p
        {
            continue;
        }
        else
        {
            s[i] = p[k];//copy "Artillery" pointer to s
            k+=3;
            i++;
        }
    }
    else
    {
        if(l>11) //means no more cavalary cards due to pattern in p
        {
            continue;
        }
        else
        {
            s[i] = p[l]; //copy "Cavalry" pointer to s
            l+=3;
            i++;
        }
    }
}
}

现在我的问题是我正在尝试创建一个绘制方法,从s抓取指针并返回它。当我尝试这个时,我的程序完全崩溃了,我不确定原因:

CardTypes* Deck::draw() //draws a card from the deck and returns it
{
CardTypes* card = s[deckSize];
delete s[deckSize];//clear heap
s[deckSize] = NULL;//remove what pointer was pointing too (as card has been drawn)
deckSize--;
return card;
}

然后我尝试调用这个方法:`

int main()
{
Deck d1;
d1.shuffle(); //this works
d1.getCurrentDeck();//this works, just prints out each objects getCard() method in s
CardTypes* card = d1.draw();//does not cause a crash
cout<<"Card:"<<card->getCard() <<"\n";//crashes here
}

这个问题可能是由于我对指针缺乏经验,但任何帮助都会受到赞赏。还要注意我在使用delete [] p和delete [] s完成程序后删除了数组,我没有在代码中包含它,因为它现在不是问题。

2 个答案:

答案 0 :(得分:0)

您的问题是您正在删除该实例,之后您想要使用它。

您正在创建许多实例:

for(int i=0;i<deckSize;i+=3) //deckSize=12 in this case, p defined as CardTypes* p[deckSize]
{
    p[i]= new Infantry(); 
    p[i+1] = new Artillery();
    p[i+2] = new Cavalry();

}

数组的大小由变量deckSize确定。

在您的函数Deck::draw()中,您有一些错误:

  • 您使用以下代码设置了CardType实例的指针:CardTypes* card = s[deckSize]; 但数组s的索引基数为0,因此s[deckSize]正在访问另一个未分配给数组的内存扇区(可能存在内存访问冲突)。使用s[deckSize-1]代替s[deckSize]

  • 您释放分配给指针card的内存,并返回此指针以在函数外部使用,该函数尝试使用此实例但不再存在。因此释放了cards[deckSize]共享的内存。 不要忘记s[deckSize]可能会引发内存访问冲突

检查您的代码:

CardTypes* Deck::draw() //draws a card from the deck and returns it
{
  CardTypes* card = s[deckSize-1];  //Assign the pointer to card.
  delete s[deckSize-1];//DELETE THE INSTANCE (The memory that 

  return card; //The card points to a memory previously released.
}

以下是您尝试使用未分配的时刻:

CardTypes* card = d1.draw();//Get the pointer to s[deckSize-1]
cout<<"Card:"<<card->getCard() <<"\n";//crashes here

<强>更新

回答你的评论,你可以这样做:

1 .- 获取实例的引用:CardTypes* card = s[deckSize-1];

2 .- 将数组的插槽设置为NULL并减小索引:

s[deckSize-1]=NULL;
deckSize--;.

3 .- card中保存的引用返回到上一级:return card;

4 .- 根据需要使用返回的引用:

CardTypes* card = d1.draw();
cout<<"Card:"<<card->getCard() <<"\n";.

5 .- 最后,在完成使用后删除de instance,例如在调用getCard()之后:

cout<<"Card:"<<card->getCard() <<"\n";
delete card;

重要的是要说你决定在何时何地保留,使用和释放记忆;请记住以有组织的方式执行此操作并应用最佳实践,例如:

https://www.codeproject.com/Articles/13853/Secure-Coding-Best-Practices-for-Memory-Allocation http://www.embeddedstar.com/technicalpapers/pdf/Memory-Management.pdf

答案 1 :(得分:0)

你正在努力争取指针所有权。您了解在C ++中必须删除不再需要的指针,但在Deck::draw中,您仍然需要删除指针。

CardTypes* Deck::draw()
{
    CardTypes* card = s[deckSize]; // s and card point to same allocation
    delete s[deckSize]; // boom! card points to garbage.
    s[deckSize] = NULL;
    deckSize--;
    return card;
}

你可以使用原始指针,但你需要在编码成熟度和审议程度很高的情况下完成。

或者你可以说Smurf它并用智能指针保护自己免受这样的事故。 What is a smart pointer and when should I use one?

std::unique_ptr捆绑指针的所有权。一次只允许一个std::unique_ptr。你无法复制它。它被移动到任何地方,将所有权从一个持有者转移到另一个持有者。但最终there can be only one。你必须用unique_ptr来愚弄自己。制作五个unique_ptr并将它们指向同一个指针,是的,你可以做到这一点。在@ unique_ptr中放置一个自毁变量自动变量,是的,你可以这样做(有时你会这样做,但是使用一个什么都不做的自定义删除器。)

unique_ptr是指针的所有者。拥有unique_ptr的人是代理所有者,因为只要他们摆脱unique_ptr,指针就会随之而来。

让我们来看看我们可以用std::unique_ptr<CardTypes>做些什么来保护这些野性指针。如果sunique_ptr的数组std::unique_ptr<CardTypes> s[MAX_DECK_SIZE];,则draw成为

std::unique_ptr<CardTypes> Deck::draw()
{
    std::unique_ptr<CardTypes> card = std::move(s[deckSize]);
    // delete s[deckSize]; don't. Card now owns the card
    // s[deckSize] = NULL; handled by moving ownership
    deckSize--;
    return card;
}

这可以简化为

std::unique_ptr<CardTypes> Deck::draw()
{
    return std::move(s[deckSize--]);
}

decksize--是一个帖子减量,因此它会在unique_ptr移出s后由s[i] = p[j]; 管理,其余的工作由s[i] = std::move(p[j]); 完成;

可悲的是,这意味着

p

不再那么容易了。你需要

j

但只有s[i]不再需要p元素,因为unique_ptr现在拥有它,宝贝。

问题提供的信息太少,无法正确地解决这个问题,但是......

你很有可能让s充满p s并加载s生命指针,其生命周期由delete管理并通过p因为你知道p有你的背,所以在没有s它们的情况下,指向裸体和自由的指针。只要你保持s的时间长于p,而Card的任何人都会指向。s[i] = std::move(p[j]); 。这一切都回到了所有权,在这种情况下,s[i] = p[j].get(); 拥有所有CardTypes * Deck::draw() { return s[deckSize--]; }

转过来


<meta name="viewport" content="width=device-width, initial-scale=1">

.container

并绘制成

return

让生活变得非常轻松。