【问题标题】:Using overloaded << operator with dynamic array将重载的 << 运算符与动态数组一起使用
【发布时间】:2015-02-21 09:42:00
【问题描述】:

我的问题如下:

我想使用重载的 >> 运算符将文件中的值读取到名为 Voter 的特定类的动态数组中。 然后,我想将我的结果导出到屏幕上,用另一个重载的

使用普通数组,我得到了即时结果,但在动态化方面遇到了困难。 我在论坛上读到向量可能是一种更好的方法,但我想了解我在这方面做错了什么。

谢谢!

详情:

该文件有 3 个用空格分隔的“值”: id(string) nr(int) (1 or 0)bool

代码摘录:

string RollFileName = "VotersRoll.dat";
ifstream inFile_VotersRoll;
inFile_VotersRoll.open(RollFileName);

if(inFile_VotersRoll.fail())
{
    printf("The VotersRoll.dat file failed to open.\n");
    exit(1);

}
//connect to in file



int numberOfEntries = 0;
Voter testVoter;
while(inFile_VotersRoll>>testVoter)
{
    numberOfEntries++;
}
//get number of voter objects from file

typedef Voter* VoterArrayPntr;
VoterArrayPntr rollArray;
rollArray = new Voter[numberOfEntries];
//create dynamic arrray for voter objects


while (inFile_VotersRoll>>*rollArray) {
    cout << *rollArray;

}

类(摘录):

class Voter
{
public:
    friend istream& operator>>(istream &inP, Voter &voterP);
    friend ostream& operator<<(ostream &outP,const Voter &voterP);
private:
    string id;
    int nr_times_voted;
    bool voted;
}

好友功能:

istream& operator>>(istream &inP,Voter &voterP)
{  
   inP >> voterP.id >> voterP.nr_times_voted >> voterP.voted;
   return inP; 
}
ostream& operator<<(ostream &outP,const Voter &voterP)
{ 
   outP << voterP.id << voterP.nr_times_voted << voterP.voted;   
   return outP;
}

【问题讨论】:

  • 您的输入、输出和错误信息是什么?请阅读this
  • 感谢 philipxy - 没有真正收到任何错误消息:我正在阅读此内容(VotersRoll.dat 文件数据):19810102009 1 0 19792003008 2 0 19851010890 3 1 19900909897 2 0 19561812567 6 1 目前只有输出:程序以退出代码结束:0
  • @Gpoo 请编辑您的问题以提供此类附加信息。如您所见,它在评论中的可读性不是很好。
  • 第一次阅读后是否“倒回”文件?
  • @JoachimPileborg 感谢 Joachim。不,我没有。这似乎是问题所在。关于如何实现这一目标的任何指导?刚开始接触 c++,所以还在学习细节。

标签: c++ arrays dynamic operators


【解决方案1】:

在 C++ 中,std::vector 实现了动态数组的概念。这不仅仅是“也许”更好的方法。 不要使用new[]delete[]

(实际上,您的示例代码中完全缺少delete[]。如果您不在任何地方释放内存,并且只要程序运行,该对象在概念上并不意味着存在,那么这就是内存泄漏。)

至于为什么这里的代码不起作用,我们先来看看这个循环:

int numberOfEntries = 0;
Voter testVoter;
while(inFile_VotersRoll>>testVoter)
{
    numberOfEntries++;
}

这很奇怪;您第一次读取整个文件只是为了获取元素的数量,然后会再次读取它以获取实际元素?

这是多余的。您应该在一个循环中获得所有内容。

但是这里也有两个严重的bug:

  1. 在第二个循环开始之前,您已到达文件末尾
  2. 您只使用数组的第一个元素

让我们先解决第一个问题。在下一个循环中,

typedef Voter* VoterArrayPntr;
VoterArrayPntr rollArray;
rollArray = new Voter[numberOfEntries];
//create dynamic arrray for voter objects

while (inFile_VotersRoll>>*rollArray) {
    cout << *rollArray;
}

循环条件永远不会为真。您的 operator&gt;&gt; 被调用一次。流从运算符返回。最后,它被用在循环条件中,导致false——因为你已经在文件的末尾了。

一个非常快速的解决方法是为同一个文件打开一个新流来解决这个问题:

typedef Voter* VoterArrayPntr;
VoterArrayPntr rollArray;
rollArray = new Voter[numberOfEntries];
//create dynamic arrray for voter objects

ifstream inFile_VotersRoll2; // ugly workaround
inFile_VotersRoll2.open(RollFileName);
while (inFile_VotersRoll2>>*rollArray) {
    cout << *rollArray;
}

这将读取并打印整个文件。但是,所有内容都将仅从数组的第一个元素读取和写入。 *rollArray 指的是第一个元素,rollArray 永远不会改变。

第二个错误是这样修复的:

for (int index = 0; (index < numberOfEntries) && (inFile_VotersRoll2>>rollArray[index]); ++index) { 
    cout << rollArray[index];
}

但正如我之前所说,您的目标应该是一次阅读整本书。这意味着您可以随时增加数组的大小。幸运的是,有了std::vector,这很简单,因为std::vector 不仅会自动增长,in a clever way 也会自动增长。并且内存也会自动释放。我们开始吧,您的完整示例已修改为使用std::vector

#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <stddef.h>

using namespace std; // just for quick'n'dirty test code

class Voter
{
public:
    friend istream& operator>>(istream &inP, Voter &voterP);
    friend ostream& operator<<(ostream &outP,const Voter &voterP);
private:
    string id;
    int nr_times_voted;
    bool voted;
};

istream& operator>>(istream &inP,Voter &voterP)
{  
   inP >> voterP.id >> voterP.nr_times_voted >> voterP.voted;
   return inP; 
}
ostream& operator<<(ostream &outP,const Voter &voterP)
{ 
   outP << voterP.id << voterP.nr_times_voted << voterP.voted;   
   return outP;
}

int main() {

    string RollFileName = "VotersRoll.dat";
    ifstream inFile_VotersRoll;
    inFile_VotersRoll.open(RollFileName);

    if(inFile_VotersRoll.fail())
    {
        std::cerr << "The VotersRoll.dat file failed to open.\n";
        return EXIT_FAILURE;
    }

    std::vector<Voter> voters;

    Voter input;
    while (inFile_VotersRoll >> input) {
        voters.push_back(input);
    }

    for (auto const &voter : voters) {
        std::cout << voter << "\n";
    }
}

【讨论】:

  • 谢谢克里斯蒂安。这真的帮助了我很多。还在学习中,所以这种类型的帖子很有帮助!另一个问题:在我的源文件中,我基本上有一个矩阵(第一列:字符串,第二列:整数,第三列:bool)如何在使用向量时读取第 2 列和第 3 列?
  • @Gpoo:您将拥有大小为 width*height 的 std::vector&lt;std::vector&lt;T&gt;&gt;std::vector&lt;T&gt;,并带有额外的逻辑来计算正确的偏移量。在这两种情况下,您都可以将向量包装在 Matrix 类中以封装额外的复杂性。见stackoverflow.com/questions/27656251/…
【解决方案2】:

“我想了解我在这个问题上做错了什么。”

你的循环在这里

while (inFile_VotersRoll>>*rollArray) {
    cout << *rollArray;
}

只会写入数组中的第一个元素。读入后需要增加指向下一个元素的指针:

inFile_VotersRoll.seekp(0); // Rewind to the beginning of inFile_VotersRoll

VoterArrayPntr curItem = rollArray;
while (inFile_VotersRoll>>*curItem) {
    cout << *curItem;
    curItem++; // <<<<<<
}

【讨论】:

  • 这样做的问题当然是原来的指针丢失了。
  • 谢谢 πάντα ῥεῖ,我试过了,但仍然没有显示任何内容。也许我可以尝试其他任何建议?
  • @Gpoo " 但仍然没有显示任何内容",那肯定是另一个问题。
  • @Gpoo 你必须重置inFile_VotersRoll的读指针,在你统计了条目数之后:inFile_VotersRoll.seekp(0);
猜你喜欢
  • 2016-03-16
  • 1970-01-01
  • 1970-01-01
  • 2013-11-29
  • 1970-01-01
  • 2017-10-12
  • 1970-01-01
  • 2014-11-19
  • 1970-01-01
相关资源
最近更新 更多