2016-03-21 81 views
-4

我正在用C++編寫程序,遇到了最奇怪的錯誤。我的程序在主要返回0之前崩潰。返回前主崩潰0

我不明白程序在完成之後如何崩潰,但在返回零之前崩潰。

這怎麼可能?

主要是以下幾點:

#include <iostream> 
#include <iomanip> 
#include <utility> 
#include <ctime> 
#include "Text.h" 
#define TIME(start, end) double((end) - (start))/CLOCKS_PER_SEC 


int main(int argc, char* argv[]) { 
    argv[1] = "gutenberg_shakespeare.txt"; 
    argc = 2; 

    if (argc == 1) { 
     std::cerr << argv[0] << ": missing file operand\n"; 
     return 1; 
    } 
    else if (argc != 2) { 
     std::cerr << argv[0] << ": too many arguments\n"; 
     return 2; 
    } 

    std::clock_t cs, ce; 
    std::cout << std::fixed << std::setprecision(3); 

    cs = std::clock(); 
    w3::Text a; 
    ce = std::clock(); 
    std::cout << "Constructor  " << TIME(cs, ce) << " seconds"; 
    std::cout << " - a.size = " << a.size() << std::endl; 

    cs = std::clock(); 
    w3::Text b(argv[1]); 
    ce = std::clock(); 
    std::cout << "Constructor  " << TIME(cs, ce) << " seconds"; 
    std::cout << " - b.size = " << b.size() << std::endl; 

    cs = std::clock(); 
    a = b; 
    ce = std::clock(); 
    std::cout << "Copy Assignment " << TIME(cs, ce) << " seconds"; 
    std::cout << " - a.size = " << a.size() << std::endl; 

    cs = std::clock(); 
    a = std::move(b); 
    ce = std::clock(); 
    std::cout << "Move Assignment " << TIME(cs, ce) << " seconds"; 
    std::cout << " - a.size = " << a.size() << std::endl; 

    cs = std::clock(); 
    w3::Text c = a; 
    ce = std::clock(); 
    std::cout << "Copy Constructor " << TIME(cs, ce) << " seconds"; 
    std::cout << " - c.size = " << c.size() << std::endl; 

    cs = std::clock(); 
    w3::Text d = std::move(a); 
    ce = std::clock(); 
    std::cout << "Move Constructor " << TIME(cs, ce) << " seconds"; 
    std::cout << " - d.size = " << d.size() << std::endl; 

    cs = std::clock(); 
    ce = std::clock(); 
    std::cout << "Destructor  " << TIME(cs, ce) << " seconds\n"; 

    std::cout << "DONE"; 
    return 0; 
} 

文本cpp文件:

#include "Text.h" 
#include <fstream> 
#include <iostream> 

using namespace w3; 

Text::Text() { 

} 

//MOVE Copy constructor 
Text::Text(Text&& movefrom){ 
    std::cout << "MOE COPY CONSTRUCTOR" << std::endl; 
    filename = movefrom.filename; 
    entries = movefrom.entries; 
    data  = movefrom.data; 

    movefrom.entries = 0; 
    movefrom.data = nullptr; 
} 

//move assig operator 
Text&& Text::operator=(Text&& movefrom) { 
    std::cout << "move assig operator" << std::endl; 

    if (&movefrom != this) { 
     filename = movefrom.filename; 
     entries = movefrom.entries; 

     if (data != nullptr) { 
      delete[] data; 
      entries = 0; 
     } 

     movefrom.data = nullptr; 
    } 

    movefrom.entries = 0; 
    return std::move(*this); 
} 

//constructor 
Text::Text(const std::string& mystring) { 
    std::cout << "Constructor" << std::endl; 
    int count = 0; 
    filename = mystring; 

    std::string buffer; 
    std::ifstream myfile(filename); 

    if (!myfile.is_open()) { 
     filename.clear(); 
    } 

    if(myfile.is_open()) { 

     while (getline(myfile, buffer)) { //Will fail at end of file 
      //std::cout << buffer << std::endl; 
      count++; 
     } 
     std::cout << "File is read"; 

     data = new std::string[count]; 

     myfile.clear();//.................reset file state 
     myfile.seekg(0, myfile.beg);//....reset file position 

     int x = 0; 
     for (int i = 0; i < count; i++) { 
      getline(myfile, data[i]); 

     } 

     std::cout << std::endl << "File is copied" << std::endl; 

     entries = count; 
     myfile.close(); 
    } 
} 

//default constructor 
Text::~Text() { 
    if (data != nullptr) { 
     delete[] data; 
     entries = 0; 
    } 
    data = nullptr; 
} 

//copy constructor 
Text::Text(const Text& copyfrom) { 
    data = nullptr; //The object is empty 
    *this = copyfrom; 
} 

const Text& Text::operator=(const Text& copyfrom) { 
    std::cout << "copy assign operator" << std::endl; 

    if (this != &copyfrom) { 

     if (data != nullptr) { 
      delete[] data; 
      entries = 0; 
     } 
     filename = copyfrom.filename; 
     entries = copyfrom.entries; 
     if (copyfrom.data != nullptr) { //If the object is not empty 
      data = new std::string[entries]; 
      for (int i = 0; i < entries; i++) { 
       data[i] = copyfrom.data[i]; 
      } 
     } 
     std::cout << "Data is assigned" << std::endl; 
    } 

    return *this; 
} 


size_t Text::size() const { 
    return entries; 

} 

void Text::print() { 

    for (int i = 0; i < entries; i++) { 
     std::cout << data[i] << std::endl; 
    } 

} 

編輯>>>頭文件

#ifndef TEXT_H 
#define TEXT_H 


#define FILE_LENGTH 10 

#include <string> 
#include <iostream> 


namespace w3 { 

    class Text { 

    private: 
     std::string filename; 
     std::string * data = nullptr; 
     size_t entries; 

    public: 
     Text(Text&& movefrom); 
     Text&& operator=(Text&& movefrom); 

     Text(); 
     Text(const std::string& mystring); 
     Text(const Text& copyfrom); 
     ~Text(); 

     const Text& operator=(const Text& copyfrom); 

     size_t size() const; 

     void print(); 
    }; 
} 

#endif 
+1

任何錯誤信息? –

+1

我敢打賭,這不是一個簡單的例子。 – MSalters

+0

它在哪一點崩潰? – SolaGratia

回答

1

我不得不說,失敗不是我所期待的。對此表示讚賞。我期望雙重刪除,因爲兩個對象指向同一個池。因此,這不是普通的原因Rule of Three violation;它有點不同。

快速瀏覽說明覆制邏輯是好的(如果可以的話,可以考慮使用std::vector來處理數據)如果你這樣做的話,你可以丟掉大約1/4的代碼。而大死亡點是一個不完整的默認構造函數。

w3::Text a; 

將調用裸機默認構造函數

Text::Text() { 

} 

這並不初始化datanullptr。在這裏,這會導致問題const Text& Text::operator=(const Text& copyfrom)

if (data != nullptr) 
{ 
    delete[] data; 
    entries = 0; 
} 

a=b;a.data從未設置過,不太可能是nullptr,並且將嘗試釋放存儲不屬於它。如果程序設法勉強完成了這一步,並且它可以,它的狀態現在是無效的,Crom只知道它什麼時候會失敗。

Text::Text(): entries(0), data(nullptr) 
{ 

} 

解決了這個問題。

也...

拷貝構造函數泄漏

Text::Text(const Text& copyfrom) 
{ 
    data = nullptr; //The object is empty 
    *this = copyfrom; 
} 

你怎麼知道的數據是空的?沒有測試,所以噗!如果有什麼東西,現在就無法到達。但正如Paul McKenzie在上面指出的那樣,根據Copy構造函數編寫賦值運算符幾乎總是更好。

移動賦值運算符有點不可靠。

Text&& Text::operator=(Text&& movefrom) 

大概應該是

Text& Text::operator=(Text&& movefrom) 

這意味着你不必清除thisreturn std::move(*this);。只是return *this;

在析構函數沒有點

data = nullptr; 

的對象是該行後立即銷燬,所以歸零data是白費功夫。

+0

我越來越習慣Java,這使得使用C++更加困難。事情經常崩潰,沒有給出任何跡象表明原因。 – bigcodeszzer

+0

@bigcodeszzer遠離原始指針並開始使用容器類和智能指針。然後,C++可以變得更容易使用,幾乎與Java一樣簡單,因爲您不必編寫所有代碼來維護類。如果你這樣做了,你很可能不會遇到你所遇到的問題。使用'std :: vector '替換'std :: string *'成員將是使用容器類而不是原始指針的主要示例。 – PaulMcKenzie

+0

這是有道理的。我雖然在學校,但他們希望我們知道如何首先使用所有裸露的骨頭。我只是精神抖I我可以使用字符串,而不是char *。 – bigcodeszzer