2017-01-07 5 views
-3

私はクラスIStream2を持っている:2番目のオブジェクトを初期化すると、最初のオブジェクトが変更されるのはなぜですか?

class IStream2 { 
    private: 
     char* fn; 
    public: 
     IStream2(char* filename); 
     char* get_filename(); 
}; 


IStream2::IStream2(char *filename) { 
    strcpy(fn, filename); 
} 
char * IStream2::get_filename() { 
    return fn; 
} 

そしてここでは、メインのコードです:

vector<IStream2> istreams; 

char fn[] = "file1.txt"; 
IStream2 reader2 = IStream2(fn); 
istreams.push_back(reader2); 

char fn2[] = "file2.txt"; 
IStream2 reader3 = IStream2(fn2); 
istreams.push_back(reader3); 
cout << istreams[0].get_filename() << endl; 

それはFILE2.TXT出力しますが、私はFILE1.TXTを期待。 私は文字列を使うべきだと知っていますが、この問題を解決したいと思います。

+7

どのようにfnのストレージを割り当てましたか? (したがってstrcpyはどこかにコピーされます) – Jimmy

+0

どちらの場合でも 'fn'を使用している可能性がありますか?第2の 'char *'の名前を変更してください –

+2

'fn'を2回定義したので、そのコードは正しくありません。問題の原因となる実際のコードを教えてください。また、 'fn'メンバを割り当てようとします。 –

答えて

2
IStream2::IStream2(char *filename) { 
    strcpy(fn, filename); 
} 

fnの記憶域は割り当てられません。 strcpy(fn, filename);は、未定義のビヘイビアを何らかの記憶域に書き込むと、fnがポイントし、その後はすべてのベットがオフになります。プログラムは何でもできる。

正しい答えはstd::string

class IStream2 { 
private: 
    std::string fn; 
public: 
    IStream2(const char* filename); // note const. if not modifying a passed rference, 
            // mark it const. The compiler can make optimizations 
            // and can catch mistakes for you 
            // also the function can now receive string literals 
    const char* get_filename(); // another const this is because a string won't 
           // easily give you a non const pointer 
}; <-- note the added ; 

IStream2::IStream2(const char *filename): fn(filename) { 
} 
const char * IStream2::get_filename() { 
    return fn.c_str(); // get the char array from the string 
} 

を使用することです。しかし、私はそう戻って、我々は行く石器時代に、これはクラスとCを書くことの練習である疑いがあります。私たちは自分ですべてのメモリを管理しなければならないので、これ以上の作業はありません。たとえば、3つのルールを守る必要があります。 What is The Rule of Three?

私たちが恐竜とwrestingされているので

class IStream2 { 
private: 
    char* fn; 
public: 
    IStream2(const char* filename); // note const char * 
    ~IStream2(); // need destructor to clean up fn. This means we need to 
       // comply with the Rule of Three 
    IStream2(const IStream2 & src); // copy constructor 
    IStream2 & operator=(IStream2 src); // assignment operator 
    char* get_filename(); // Note: by returning a non const pointer here we 
          // allow the caller to tamper with the contents of 
          // fn and even delete it. This defeats the point 
          // of declaring fn private, so avoid doing this. 
}; 

IStream2::IStream2(const char *filename) { 
    fn = new char[strlen(filename) +1]; // allocate storage. 
             // The +1 is to hold the string's NULL terminator 
    strcpy(fn, filename); 
} 
// implement copy constructor 
IStream2::IStream2(const IStream2 & src) { 
    fn = new char[strlen(src.fn) +1]; 
    strcpy(fn, src.fn); 
} 
// implement destructor 
IStream2::~IStream2() 
{ 
    delete[] fn; 
} 
// implement assignment operator. Using Copy And Swap Idiom 
IStream2 & IStream2::operator=(IStream2 src) 
{ 
    std::swap(fn, src.fn); 
    return *this; 
} 
char * IStream2::get_filename() { 
    return fn; 
} 


int main() 
{ 
    vector<IStream2> istreams; 

    const char* fn = "file1.txt"; // note const char *. string literals may be 
            // read-only memory and can't be changed 
    IStream2 reader2 = IStream2(fn); 
    istreams.push_back(reader2); 

    const char* fn2 = "file2.txt"; // and again const char * 
    IStream2 reader3 = IStream2(fn2); 
    istreams.push_back(reader3); 
    cout << istreams[0].get_filename() << endl; 
    return 0; 
} 

、私はRule of Fiveを気にして操作を移動し、それはこの間違った方法をしなければならないことですどれだけ多くの迷惑は表示されませんか?

詳細については、Copy And Swap Idiom

関連する問題