【问题标题】:c++ list traversing and initializationc++列表遍历和初始化
【发布时间】:2014-02-10 21:33:38
【问题描述】:

我大部分时间都在使用托管代码进行编程,并且我有兴趣回到 C++。 一直在到处敲我的头(在谷歌上)寻找答案。 所以我开始在这里做练习:http://www.cplusplus.com/forum/articles/12974/ 并偶然发现了很多错误。 我尝试了可乐机(第二台),它给了我制作可乐机的想法,并尝试用 pointers 初始化 Machine 中的列表喝

我不想使用 Boost 库,因为我想了解容器的工作原理(尤其是列表)。

我会在问题之后发布我的代码:

1) 我在(*it)->getDrinkName() 行中收到以下错误 EXC_BAD_ACCESS 关于方法:getDrinkName() in Drink.cpp 为什么会这样?我没有用饮料正确初始化列表吗?

当我尝试这个时:

Drink* test = new Drink("Coke");
cout << test->getDrinkName();

它有效。是我在 Drink 中的构造函数让它崩溃了吗?

2) 我想在 Machine 的构造函数中初始化列表吗?喜欢:

_list = new list<Drink *>();

3) 这是代码:

Drink.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;
};

机器.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;
}

提前谢谢!

【问题讨论】:

  • 哎呀,我忘记删除了,我在这里添加了它!谢谢。我知道我可以像他们使用的所有教程一样取出所有动态分配,如 list... 但我想将指针放在列表中,然后最终使用 boost,但现在我想知道它为什么会崩溃那个地方。
  • @juanchopanza 虽然我同意他应该避免动态分配,但这不是问题的根源,这是迭代器范围的问题。
  • @bachibusuc 添加delete 只会让代码变得更糟。真正退后一步,从一本好的 C++ 书籍开始。
  • &lt;rant&gt; 伙计们,不管指针是个好主意还是坏主意,C++ 初学者都必须知道它们是如何工作的,因为在没有智能指针的情况下开发的代码已经有 40 多年了.每当您看到指针时,简单地将问题记为指针不仅没有帮助,而且也不能教人们如何正确使用指针,而且通常是卑鄙的。 &lt;/rant&gt;
  • @pmr 我想我可以使用这个解决方案:stackoverflow.com/a/307121/2081433

标签: c++ list


【解决方案1】:

首先,std::list 应该是容器中需要了解的最后一个优先级。其次,显式使用动态分配的优先级应该比这更低。

如果我要模拟一台软饮料机,我可以合理地猜测,在我编写的任何内容中,您都找不到单个显式指针 newdelete 或迭代器。我的第一个(公认是简化的)版本可能看起来像这样:

#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++ 实践开始,混入最糟糕的“托管”代码,最后得到一个几乎没有runs 跛行的难以理解的混乱。

我的建议是,如果你要尝试编写 C++,而不是从“我将使用 list 和指针”之类的心态开始,而是从“什么是最简单的”开始最有效的方法来解决这个问题?”并采取相应的行动。

如果您对该有效解决方案的印象包括任何原始指针或 listnewdelete 的使用,那么您可能应该立即停下来,做更多的阅读和/或思考,因为任何事情这是一个相当可靠的迹象,表明你可能根本没有足够的知识来很好地解决当前的问题。如果再多阅读一些书并不能让您摆脱困境,那么您很可能正在阅读一本糟糕的书——不幸的是,关于 C++ 的 书几乎是稀有的(您可能想查看C++ Book List 推荐)。

【讨论】:

  • 不用担心,感谢您的评论和解决方案。正如我所说,我正在挖掘内部。我本可以像你一样在主函数中完成它(尤其是练习很简单),但我只是想看看标题、类甚至指针是如何工作的。只是这个例子帮助我查看并解读了 MadScienceDreams 提到的价值/参考回报。
【解决方案2】:

问题是您按值返回容器,而不是引用。 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)),我们会得到您看到的错误。

【讨论】:

  • 那实际上不应该改变列表中的 Drink* 吗?所以,这是一个他应该解决的问题,但我认为不是导致崩溃的问题?
  • @TJBandrowsky 问题是 int cout &lt;&lt; (*it)-&gt;getDrinkName(); 指向它的迭代器超出范围。我会在我的回答中更明确地说明这一点
  • 成功了!我将阅读更多关于参考/价值回报的信息。再次感谢!
【解决方案3】:

我想说,要找出答案,请在您的循环中执行此操作:

auto x = *it;
cout << x->getDrinkName();
delete x;

如果您在 auto x 行设置断点,您应该能够查看 x 是否等于您之前定义的 testCoke。它们应该是相同的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多