使用继承的指针列表复制构造函数或重载 Operator=
Copy Constructor or overloading Operator= with an inherited list of pointers
我有一个继承自指针列表的 Class,例如:
Class C : protected list<Type*>
现在,我想重载 operator=(并编写复制构造函数)。我应该迭代列表为列表中的每个指针创建一个新类型吗?
void C::operator=(const C& c)
{
if(!(*this)==c))
{
clear();
for(list<Type*>::iterator it = c.begin(); it != c.end(); it++)
{
Type* cp = new Type((*it)); //or doing cp=&(*it) after the new
push_back(cp);
}
}
}
或者我可以这样做吗?
void C::operator=(const C& c)
{
if(!(*this)==c))
{
clear();
for(list<Type*>::iterator it = c.begin(); it != c.end(); it++)
{
Type* cp = it; //or cp=&(*it)
push_back(cp);
}
}
}
我已经编辑了我的答案,因为这是作业练习
在正常的应用程序中,您不应从 STL 容器派生,它们的析构函数不是虚拟的。因此,当 C
被销毁时, std::list<T>
将保留,从而导致内存泄漏。首先,它们并不意味着继承形式...
在正常设计中,您会将列表作为对象:
#include <list>
template<typename T>
class C {
private:
std::list<T*> lst;
public:
C& operator=(const C& c) {
if (this != &c) {
lst = c.lst;
}
return *this;
}
};
我认为 GOOD 练习是您实施 MyList
class,使 一切从头开始。
但众所周知,教授会让学生做一些奇怪的不合逻辑的事情。所以让我们假设你确实想从 std::list
派生并且只重载 operator=
,自己做复制
#include <list>
template<typename T>
class C : protected std::list<T*>
{
public:
constexpr C& operator=(C const& c) noexcept {
if (this != &c) {
this->clear();
// copy
}
return *this;
}
};
现在,你如何复制...多种口味!有一个古老的 C 风格循环:
for (int i = 0; i < c.size(); ++i) this->push_back(c[i]);
有迭代器循环:
for (std::list<T*>::const_iterator it = c.cbegin(); it != c.cend(); ++it) this->push_back(*it);
有迭代器循环 auto
和通用访问器:
for (auto it = std::cbegin(c); it != std::cend(c); ++it) this->push_back(*it);
有基于范围的 for 循环:
for (auto const& el : c) this->push_back(el);
有算法,比如std::for_each
std::for_each(std::cbegin(c), std::cend(c), [this](T* ptr) { this->push_back(ptr); });
... 和 std::copy
std::copy(std::cbegin(c), std::cend(c), std::back_inserter(*this));
请注意 std::back_inserter
是一个迭代器,它在迭代时执行 push_back
。
在未来 (C++20) 我们将有范围,所以你可以这样写
std::ranges::copy(c, *this);
虽然我不确定这是否正确...
选择你的毒药!
这取决于你想做什么!
第一个执行深拷贝;第二个只是执行列表中指针的浅拷贝,因此没有做原始 std::list
实现没有做的任何事情。
还有,if(!(*this)==c))
是错误的;它有太多 )
并且可能是 if (this != &c)
.
我有一个继承自指针列表的 Class,例如:
Class C : protected list<Type*>
现在,我想重载 operator=(并编写复制构造函数)。我应该迭代列表为列表中的每个指针创建一个新类型吗?
void C::operator=(const C& c)
{
if(!(*this)==c))
{
clear();
for(list<Type*>::iterator it = c.begin(); it != c.end(); it++)
{
Type* cp = new Type((*it)); //or doing cp=&(*it) after the new
push_back(cp);
}
}
}
或者我可以这样做吗?
void C::operator=(const C& c)
{
if(!(*this)==c))
{
clear();
for(list<Type*>::iterator it = c.begin(); it != c.end(); it++)
{
Type* cp = it; //or cp=&(*it)
push_back(cp);
}
}
}
我已经编辑了我的答案,因为这是作业练习
在正常的应用程序中,您不应从 STL 容器派生,它们的析构函数不是虚拟的。因此,当 C
被销毁时, std::list<T>
将保留,从而导致内存泄漏。首先,它们并不意味着继承形式...
在正常设计中,您会将列表作为对象:
#include <list>
template<typename T>
class C {
private:
std::list<T*> lst;
public:
C& operator=(const C& c) {
if (this != &c) {
lst = c.lst;
}
return *this;
}
};
我认为 GOOD 练习是您实施 MyList
class,使 一切从头开始。
但众所周知,教授会让学生做一些奇怪的不合逻辑的事情。所以让我们假设你确实想从 std::list
派生并且只重载 operator=
,自己做复制
#include <list>
template<typename T>
class C : protected std::list<T*>
{
public:
constexpr C& operator=(C const& c) noexcept {
if (this != &c) {
this->clear();
// copy
}
return *this;
}
};
现在,你如何复制...多种口味!有一个古老的 C 风格循环:
for (int i = 0; i < c.size(); ++i) this->push_back(c[i]);
有迭代器循环:
for (std::list<T*>::const_iterator it = c.cbegin(); it != c.cend(); ++it) this->push_back(*it);
有迭代器循环 auto
和通用访问器:
for (auto it = std::cbegin(c); it != std::cend(c); ++it) this->push_back(*it);
有基于范围的 for 循环:
for (auto const& el : c) this->push_back(el);
有算法,比如std::for_each
std::for_each(std::cbegin(c), std::cend(c), [this](T* ptr) { this->push_back(ptr); });
... 和 std::copy
std::copy(std::cbegin(c), std::cend(c), std::back_inserter(*this));
请注意 std::back_inserter
是一个迭代器,它在迭代时执行 push_back
。
在未来 (C++20) 我们将有范围,所以你可以这样写
std::ranges::copy(c, *this);
虽然我不确定这是否正确...
选择你的毒药!
这取决于你想做什么!
第一个执行深拷贝;第二个只是执行列表中指针的浅拷贝,因此没有做原始 std::list
实现没有做的任何事情。
还有,if(!(*this)==c))
是错误的;它有太多 )
并且可能是 if (this != &c)
.