2017-03-08 210 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

你的移動構造函數不是移動什麼,我t只是複製長度和指針(意思就像默認的複製構造函數一樣)。這意味着您將有兩個Container對象,其中的data成員將指向相同的內存。

當內存被刪除的對象之一,導致未定義的行爲當第二個對象試圖刪除相同的內存。

一個簡單的辦法解決這一問題是設置其他對象length爲零並且其data指針nullptr。或者默認初始化當前對象,然後交換這兩個對象。

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); 
    } 
}