2017-04-13 80 views
0

我一直在努力解决一些学校问题,并且我在operator>>中关心内存分配,但看到了不同的解决方案,所以我在这里有点困惑。operator>>当编译工作良好,提供良好的输出,但我不明白为什么,这里是代码.. (为什么我糊涂了是下面的代码)动态内存分配和输入(流)运算符C++

class Some 
    { 
    protected: 
     char *name; 
     int price; 
     int anything; 
    public: 
     Some(const char *name="", const int anything=0, const int price=0) 
     { 
      this->name=new char[strlen(name)+1]; 
      strcpy(this->name, name); 
      this->anything = anything; 
      this->price=price; 
     } 
     ~Some() { delete [] name; } 
     friend istream &operator>>(istream &in, Some &i) 
     { 
      return in>>i.name>>i.anything>>i.price; 
     } 
     void print(){ 
      cout << name << " " << anything << " " << price; 
     } 
    }; 

主要

int main() { 
    // your code goes here 
    Some n; 
    cin >> n; 
    n.print(); 
    return 0; 
} 

所以与Some n我们做了一个对象,但是构造函数只分配了1个字符的内存,如果我错了,请纠正我的错误(并设置一些默认值)。之后,我们使用>> operator输入Some类型的对象,但只有一个字符分配给name,我们可以输入尽可能多的数据。下面是带有一些输入Compiled Code的编译版本。我的思想在哪里错了?或者不应该这样做。谢谢 !!

诗篇,我们不允许使用这会照顾分配的库..

+0

你的班级违反了三条规则。向char数组输入任意长度的数据是一个难题... – aschepler

+1

你是对的。该代码(可怕)被破坏。 –

+0

@aschepler是的我知道了,但这只是该课程的一部分,因为我不想将大块代码与我的问题联系在一起。 –

回答

2

缓冲区溢出(这是你在做什么,当你对一个char分配空间,但是写远远超出它与您致电std::cin >> i.name)被认为是C++中的未定义行为。这意味着编译器可以做任何事情来回应它,甚至是那些似乎无关或疯狂的东西。

在实践中,这意味着有时,你的代码将很好地工作,没有任何问题....直到您移动到不同的编译器或测试在不同的一天或当天上午有一个不同种类的咖啡,代码在这一点破坏。什么应该应该发生的是,你的代码应该抛出一个分段错误(或,在Windows中,一个访问冲突)由此代码产生,但我的猜测(我想强调这是一个猜测)是负责分配name的操作系统级调用从内存页面的早期抓取内存,并且您对未分配内存的写入在内存页的其余部分找到有效空间。

显然,你不应该依赖这种行为。根据你的帖子,你不允许使用自动内存分配方案,如std::vector<char>或(显然是正确的选择)std::string。这可能是因为你的教授 是一个白痴教你糟糕的设计原则,因为他们是一个多年来一直处于行业外的老年傻瓜,并没有赶上如何使用现代C++并打算教 试图教你如何做手动内存分配。 对于一些愚蠢的原因。 因此,您需要编写代码来处理这个问题。

该文件保罗麦肯齐链接在评论(也here)是一个很好的开始做到这一点。第3页是相关的代码。

另外,如果你的教授 有理智 突然一阵改变主意,更正后的代码应该是这样的:

class Some 
{ 
protected: 
    std::string name; 
    int price; 
    int anything; 
public: 
    //Passing by value means an optimization opportunity. We can move-construct name 
    //instead of copying it. 
    Some(std::string name = "", const int anything=0, const int price=0) : 
    //We'll use a member-initialization list to initialize everything. Saves space 
    //and saves a few CPU cycles as well! 
    name(std::move(name)), anything(anything), price(price) 
    {} 

    //We don't need to declare the destructor anymore, because name's memory is automatically 
    //managed! 
    //~Some() {} 

    //this code doesn't need to change. 
    friend std::istream &operator>>(std::istream &in, Some &i) 
    { 
     return in >> i.name >> i.anything >> i.price; 
    } 

    //This doesn't technically *need* to change, but we can do better. 
    //void print(){ 
     //cout << name << " " << anything << " " << price; 
    //} 

    friend std::ostream & operator<<(std::ostream & out, Some const& i) { 
     out << i.name << ' ' << i.anything << ' ' << i.price; 
    } 
}; 
+0

谢谢你的广泛解释(和幽默(这是事实)你在答案中实现)..我会尽力理解张贴的文件,并确保使用字符串! P.s感谢您强调成员初始化会保存一些周期(整天都在讨厌它) –

+0

isnt'std :: string'来自一个库并负责分配? – user463035818

+0

@MathNewbie imho学习使用iostreams是多么容易是人们应该学习C++的第一件事,但我恐怕你的教授是如此的老派,他不会接受一个好的解决方案,但坚持一些手动记忆管理(每一个理智的东西编码器试图尽可能避免) – user463035818

1

您正确思考的问题。

问题的解决方案涉及将字符串的长度写入输出文件,然后写入字符串的字符。

说你有对象:

name = "First Last" 
price = 15 
anything = 0 

当对象被写入时,你需要有:

10 First Last 0 15 
文件中

这给你足够的信息关于对象,让你从文件中读回来。

istream &operator>>(istream &in, Some &i) 
{ 
    size_t len; 

    // Read the length of name 
    in >> len; 

    // Allocate memory for name. 
    char* name = new char[len+1]; 

    // Read the name. 
    // Discard the whitespace first. 
    in.ignore(); 
    in.read(name, len); 

    // Now read anything and price 
    in >> i.anything >> i.price; 

    // Release memory held by i.name before using memory allocated 
    // in this function 
    delete [] i.name; 
    i.name = name; 

    return in; 
} 

Some类型的对象到一个文件中的功能具有镜像函数来读取它从文件回来。

std::ostream& operator<<(std::ostream& out, Some const& i) 
{ 
    out << strlen(i.name) << " "; 
    out.write(i.name, strlen(i.name); 
    return out << " " << i.anything << " " << i.price   
} 
+2

这可能会使问题更容易解决,而不诉诸'char'-by-'char'黑客,但从问题描述中不清楚OP允许更改输入的格式数据。如果他们的程序需要阅读他们教授提供的文本文件,这个解决方案将无法帮助他们。 – Xirema

+0

@Xirema,那是真的。 –