2017-03-08 8 views
2

私はC++を自分自身で試していますが、少し混乱しています。
私は実際にコンストラクタ/コピーコンストラクタ/コンストラクタ/デストラクタを理解し、それらを正しく設定することに問題がありました。C++ - コンストラクタ、コピーコンストラクタ、移動コンストラクタ、デストラクタ

class Containerにコピーと移動コンストラクタとデストラクタを実装したいと思います。私はコピーコンストラクタを最初に試して、それが正しいと思った。残念なことに、デストラクタでは、delete[] dataを実行しようとすると何らかの理由でプログラムがクラッシュすることがあります。 フィールドdataはもう存在しないと私は間違っていたと思う。あなたが私を助けて間違いを理解することができれば幸いです。 私は絶対に動作しない移動コンストラクタ(下)も試しました。

助けを借りてくれてありがとう。

#include <iostream> 
#include <memory> 

class Container 
{ 
public: 
Container() 
{ 
    length = 0; 
    data = nullptr; 
} 

Container(int lengthin):Container() 
{ 
    length = lengthin; 
    data = new double[lengthin]; 
    //data[lengthin]; 
    //double data[lengthin] = {0}; 
} 

Container(std::initializer_list<double> listin) 
     :Container((int)listin.size()) 
{ 
    std::uninitialized_copy (listin.begin(), listin.end(), data); 
} 

//copy constructor - working? 
Container(const Container& other):Container(other.length) 
{ 
    //data = other.data; 
    //length = other.length; 
    for (auto i=0; i<other.length; i++) 
    { 
     data[i] = other.data[i]; 
    } 
} 


//~Container(){length = 0;} 
~Container() 
{ 
    delete[] data; 
    length = 0; 
} 


Container operator+(Container cin) 
{ 
    Container cout(cin.length); 
    cout.length = cin.length; 
    for (auto i=0; i<cin.length; i++) 
    { 
     cout.data[i] = cin.data[i] + data[i]; 
    } 
    return cout; 
} 

Container operator-(Container cin) 
{ 
    Container cout(cin.length); 
    cout.length = cin.length; 
    for (auto i=0; i<cin.length; i++) 
    { 
     cout.data[i] = data[i]-cin.data[i]; 
    } 
    return cout; 
} 


void print(const std::string &info) const 
{ 
    // print the address of this instance, the attributes `length` and 
    // `data` and the `info` string 
    std::cout << " " << this << " " << length << " " << data << " " 
       << info << std::endl; 
} 

private: 
    int length; 
    double *data; 
}; 

メインプログラム:

int main() 
{ 
Container a({ 1, 2, 3 }); 
std::cout << " a has address " << &a << std::endl; 

Container b = { 4, 5, 6 }; 
std::cout << " b has address " << &b << std::endl; 

Container c(a); 
std::cout << " c has address " << &c << std::endl; 

Container d = a + b; 
std::cout << " d has address " << &d << std::endl; 

Container e; 
std::cout << " e has address " << &e << std::endl; 

e = a + b; 

//Container f(std::move(a + b)); 
//std::cout << " f has address " << &f << std::endl; 

return 0;} 

としようとした移動のコンストラクタ:

Container(const Container&& other):length(other.length), data(other.data) 

答えて

1

:)

Containerクラスに後で戻って何かを与えることができるように願っていますあなたの移動コンストラクタは移動しません何か、私長さとポインタをコピーするだけです(つまり、デフォルトのコピーコンストラクタと同じように動作します)。つまり、dataのメンバーが同じメモリを指す2つのオブジェクトを持つことになります。

メモリが削除されたオブジェクトの1つで、が未定義の動作になると、同じメモリが削除されます。

これを修正する簡単な方法は、他のオブジェクトlengthをゼロに設定し、datanullptrに設定することです。または、現在のオブジェクトをデフォルトで初期化してから、2つのオブジェクトをスワップします。

1

一部プログラマの男で説明したように、この動きのコンストラクタはどうなる:

Container(Container&& other):length(other.length), data(other.data) 
{ 
other.length = 0; 
other.data = nullptr; 
} 

other.data = nullptr;の他のデストラクタが呼び出されたときので、delete []dataは効果がありません(あなたの現在のコードとされるが保持するデータ列を無効に other.length = 0;他にもデータ配列がないので、長さも指定しないでください。 明らかにあなた自身が間違った回答を投稿したため、私はコードを投稿しました(最初の回答はそうではないようですコードが何であるべきかについて十分に明確である) また、これはコンストラクタなので、this->dataについて心配する必要はありません。移動リレーションシップ演算子を使用すると、メモリリークを避けるために、最初にdelete this->data[]にする必要があります。

コピーasignement機能は、次のようなことができます。

Container& operator=(const Container &other) 
{ 
    if (this->length) 
    delete[] this->data; 
    this -> length = other.length; 
    data = new double [this->length]; 
    for (auto i = 0; i<other.length; i++) 
    { 
     this->data[i] = other.data[i]; 
    } 
    return *this; 
} 
1

あなたのコピーコンストラクタは大丈夫です(代わりに手動ループのコピーアルゴリズムを使用して単純化することができます)。

クラスにコピー代入演算子、移動コンストラクタ、移動代入演算子がありません。

operator+operator-は、値ではなく参照によって入力を受け取り、それ自体がconstと宣言されている必要があります。また、入力Containerは、Containerとは異なるlengthが実行されている可能性があることを考慮していません。

このようなもっと何かしてみてください。

#include <iostream> 
#include <algorithm> 

class Container 
{ 
public: 
    Container() : length(0), data(nullptr) 
    { 
    } 

    Container(int len) : Container() 
    { 
     length = len; 
     data = new double[len]; 
    } 

    Container(std::initializer_list<double> src) : Container((int)src.size()) 
    { 
     std::uninitialized_copy(src.begin(), src.end(), data); 
    } 

    Container(const Container &src) : Container(src.length) 
    { 
     std::uninitialized_copy(src.data, src.data + src.length, data); 
    } 

    Container(Container &&src) : Container() 
    { 
     src.swap(*this); 
    } 

    ~Container() 
    { 
     delete[] data; 
     length = 0; 
    } 

    void swap(Container &other) noexcept 
    { 
     std::swap(data, other.data); 
     std::swap(length, other.length); 
    } 

    Container& operator=(const Container &rhs) 
    { 
     if (length < rhs.length) 
     { 
      Container tmp(rhs); 
      swap(tmp); 
     } 
     else 
     { 
      length = rhs.length; 
      std::uninitialized_copy(rhs.data, rhs.data + rhs.length, data); 
     } 
     return *this;   
    } 

    Container& operator=(Container&& rhs) 
    { 
     rhs.swap(*this); 
     return *this;   
    } 

    Container operator+(const Container &rhs) const 
    { 
     int len = std::max(length, rhs.length); 
     Container out(len); 
     for (auto i = 0; i < len; ++i) 
     { 
      if ((i < length) && (i < rhs.length)) 
       out.data[i] = data[i] + rhs.data[i]; 
      else 
       out[i] = (i < length) ? data[i] : rhs.data[i]; 
     } 
     return out; 
    } 

    Container operator-(const Container &rhs) const 
    { 
     int len = std::max(length, rhs.length); 
     Container out(len); 
     for (auto i = 0; i < len; ++i) 
     { 
      if ((i < length) && (i < rhs.length)) 
       out.data[i] = data[i] - rhs.data[i]; 
      else 
       out[i] = (i < length) ? data[i] : rhs.data[i]; 
     } 
     return out; 
    } 

    void print(const std::string &info) const 
    { 
     // print the address of this instance, the attributes `length` and 
     // `data` and the `info` string 
     std::cout << " " << this << " " << length << " " << data << " " << info << std::endl; 
    } 

private: 
    int length; 
    double *data; 
}; 

namespace std 
{ 
    void swap(Container &lhs, Container &rhs) 
    { 
     lhs.swap(rhs); 
    } 
} 

をそして、あなたは大幅に代わり、手動配列のstd::vectorを使用して物事を単純化することができます。

#include <iostream> 
#include <algorithm> 
#include <vector> 

class Container 
{ 
public: 
    Container(size_t len = 0) : data(len) 
    { 
    } 

    Container(std::initializer_list<double> src) : data(src) 
    { 
    } 

    void swap(Container &other) noexcept 
    { 
     std::swap(data, other); 
    } 

    Container operator+(const Container &rhs) const 
    { 
     size_t thislen = data.size(); 
     size_t thatlen = rhs.data.size(); 
     size_t len = std::max(thislen, thatlen); 
     Container out(len); 
     for (auto i = 0; i < len; ++i) 
     { 
      if ((i < thislen) && (i < thatlen)) 
       out.data[i] = data[i] + rhs.data[i]; 
      else 
       out[i] = (i < thislen) ? data[i] : rhs.data[i]; 
     } 
     return out; 
    } 

    Container operator-(const Container &rhs) const 
    { 
     size_t thislen = data.size(); 
     size_t thatlen = rhs.data.size(); 
     size_t len = std::max(thislen, thatlen); 
     Container out(len); 
     for (auto i = 0; i < len; ++i) 
     { 
      if ((i < thislen) && (i < thatlen)) 
       out.data[i] = data[i] - rhs.data[i]; 
      else 
       out[i] = (i < thislen) ? data[i] : rhs.data[i]; 
     } 
     return out; 
    } 

    void print(const std::string &info) const 
    { 
     // print the address of this instance, the attributes `length` and 
     // `data` and the `info` string 
     std::cout << " " << this << " " << data.size() << " " << data.data() << " " << info << std::endl; 
    } 

private: 
    std::vector<double> data; 
}; 

namespace std 
{ 
    void swap(Container &lhs, Container &rhs) 
    { 
     lhs.swap(rhs); 
    } 
} 
関連する問題