我自己在尝试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)
答案 0 :(得分:1)
你的移动构造函数不会移动任何东西,它只是复制长度和指针(意味着它就像默认的复制构造函数一样)。这意味着您将拥有两个Container
个对象,其data
成员将指向相同的内存。
当删除内存中的一个对象时,当第二个对象尝试删除相同的内存时,会导致未定义的行为。
解决此问题的一种简单方法是将其他对象length
设置为零,将data
指针设置为nullptr
。或者默认初始化当前对象,然后交换这两个对象。
答案 1 :(得分:1)
正如一些程序员老兄所解释的那样,这个移动构造函数会这样做:
Container(Container&& other):length(other.length), data(other.data)
{
other.length = 0;
other.data = nullptr;
}
other.data = nullptr;
因此,当调用其他的析构函数时,delete []data
将不起作用(当前代码会使您刚刚移动到的Container所拥有的数据数组无效。
other.length = 0;
因为其他没有数据数组,所以它也应该没有长度。
请注意,我只发布了代码,因为显然你自己发布了一个错误的答案(似乎第一个答案不清楚代码应该是什么)。
另外,因为这是一个构造函数,所以你不必担心this->data
注意,使用移动对象运算符,你必须先delete this->data[]
以避免内存泄漏。
副本设置功能可以是这样的:
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;
}
答案 2 :(得分:1)
您的复制构造函数很好(但可以使用复制算法而不是手动循环进行简化)。
您的类缺少复制赋值运算符,移动构造函数和移动赋值运算符。
您的operator+
和operator-
应该通过引用而非值来获取输入,并将它们自己声明为const
。他们也没有考虑输入Container
可能与length
的行为不同Container
。
尝试更像这样的事情:
#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);
}
}