我是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完成程序后删除了数组,我没有在代码中包含它,因为它现在不是问题。
答案 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
的内存,并返回此指针以在函数外部使用,该函数尝试使用此实例但不再存在。因此释放了card
和s[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>
做些什么来保护这些野性指针。如果s
是unique_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
让生活变得非常轻松。