我大部分时间都在用托管代码编程,我有兴趣回到C++。我(在谷歌上)到处敲来敲去,想找到答案。所以我开始在这里做练习:http://www.cplusplus.com/forum/articles/12974/犯了很多错误。我尝试了可乐机(第二台),它给了我制作可乐机的想法,并试图在Drink的指针的machine中初始化一个列表。
我不想使用Boost库,因为我想了解容器是如何工作的(尤其是列表)
我将在问题后发布我的代码:
1) 我在(*it)->getDrinkName()
行中收到以下错误EXC_BAD_ACCESS关于方法:Drink.cpp中的getDrinkName()
为什么?我没有用Drink正确初始化列表吗?
当我尝试这个:
Drink* test = new Drink("Coke");
cout << test->getDrinkName();
它是有效的。是我在Drink中的构造函数造成了崩溃吗?
2) 我应该在Machine的构造函数中初始化列表吗?类似:
_list = new list<Drink *>();
3)这是代码:
饮料.h
#include <iostream>
#include <string>
using namespace std;
class Drink
{
public:
Drink(string name);
string getDrinkName();
private:
string _name;
};
Drink.cpp:
#include "Drink.h"
Drink::Drink(string name)
{
_name = name;
}
string Drink::getDrinkName()
{
return _name;
}
机器.h
#include <iostream>
#include <list>
#include "Drink.h"
using namespace std;
class Machine
{
public:
Machine();
list<Drink*> getList() const;
private:
list<Drink*> _list;
};
Machine.cpp:
#include "Machine.h"
Machine::Machine()
{
}
list<Drink*> Machine::getList() const
{
return _list;
}
main.cpp
#include <iostream>
#include <string>
#include "Machine.h"
using namespace std;
int main () {
Machine* machine = new Machine();
Drink* testCoke = new Drink("Coke");
machine->getList().push_back(testCoke);
std::list<Drink*>::const_iterator it ;
for(it = machine->getList().begin();it!=machine->getList().end();it++)
{
cout << (*it)->getDrinkName();
delete *it;
}
return 0;
}
提前感谢!
首先,std::list
应该是要了解的容器中的最后一个优先级。其次,显式使用动态分配的优先级应该更低。
如果我要模拟一台软饮料机,很可能在我写的任何东西中都找不到一个显式指针new
、delete
或迭代器。我的第一个(公认的简化)版本可能看起来像这样:
#include <map>
#include <iostream>
#include <string>
int main() {
// Stores a Drink and a quantity of that drink.
// Establish initial stock according to drink quality.
std::map<std::string, int> machine{
{ "Coke", 2 },
{ "Mt Dew", 97 },
{ "Diet Coke", 1 }
};
std::cout << "Please insert money and select from the following list:n";
for (auto const &s : machine)
if (s.second > 0)
std::cout << s.first << "n";
std::string temp;
std::getline(std::cin, temp);
while (machine.find(temp) == machine.end()) {
std::cout << "rBad name. Please a name from the list.";
std::getline(std::cin, temp);
}
--machine[temp];
std::cout << "nEnjoy your " << temp << "n";
}
冒着听起来居高临下的风险,您当前的代码非常好地显示了您的背景。你从最糟糕的古代C++实践开始,混合最糟糕的"托管"代码,最终得到一个无法阅读的混乱,几乎没有运行。
我的建议是,如果你要尝试编写C++,而不是从"我要使用list
和指针"这样的心态开始,你应该从"解决这个问题最简单、最有效的方法是什么?"?"并采取相应行动
如果你对该有效解决方案的印象包括任何原始指针或list
、new
或delete
的使用,你可能应该立即停下来,做更多的阅读和/或思考,因为这类东西都是一个很好的迹象,表明你可能根本不知道如何很好地解决当前问题。如果更多的阅读并不能让你走出困境,那么你很可能正在读一本糟糕的书——不幸的是,关于C++的好的书籍几乎是罕见的(你可能想查看C++图书列表以获得推荐)。
问题是,返回的是值,而不是引用。machine->getList()对每个调用都进行复制,这超出了for循环的范围。更改为:
const list<Drink*>& Machine::getList() const;
编辑:更明确:
让我们看看这个:
std::list<Drink*>::const_iterator it ;
for(it = machine->getList().begin();it!=machine->getList().end();it++)
{
cout << (*it)->getDrinkName();
delete *it;
}
对machine->getList()的第一个调用创建了一个额外的列表。我们调用.begin()来获取指向该列表的第一个元素的指针。然后,该列表超出了作用域,因此它被销毁:out指针现在指向已释放的内存。迭代器(it)的副本现在指向一个无效的位置。当我们尊重它(使用*(it)
)时,我们会得到你看到的错误。
我想说,要找到答案,请在循环中执行以下操作:
auto x = *it;
cout << x->getDrinkName();
delete x;
如果你在auto x行上设置了一个断点,你应该能够看到x是否等于你之前定义的testCoke。它们应该是一样的。