一种按'new'实现分配的方法
A way to implement assignment by 'new'
使用关键字"new"有三种方法。首先是正常的方式。假设Student是一个班。
Student *pStu=new Student("Name",age);
第二条路。只请求内存空间而不调用构造函数。
Student *pArea=(Student*)operator new(sizeof(student));//
第三种方式被称为"新布局"。只调用构造函数来初始化内存空间。
new (pArea)Student("Name",age);
所以,我在下面写了一些代码。
class Student
{
private:
std::string _name;
int _age;
public:
Student(std::string name, int age):_name(name), _age(age)
{
std::cout<<"in constructor!"<<std::endl;
}
~Student()
{
std::cout<<"in destructor!"<<std::endl;
}
Student & assign(const Student &stu)
{
if(this!=&stu)
{
//here! Is it a good way to implement the assignment?
this->~Student();
new (this)Student(stu._name,stu._age);
}
return *this;
}
};
此代码适用于gcc。但我不确定它是否会导致错误,或者显式调用析构函数是危险的。打电话给你给我一些建议
"替换赋值"的问题在于它不是异常安全的。考虑一下这种简化的通用方法:
struct Foo
{
Foo & operator=(Foo const & rhs)
{
if (this == &rhs) { return *this; }
~Foo();
::new (this) Foo(rhs); // may throw!
}
// ...
};
现在,如果复制构造函数抛出异常,那么您就有麻烦了。您已经调用了自己的析构函数,因此不可避免的下一次析构函数调用将导致未定义的行为。您也无法更改周围操作的顺序,因为您没有任何其他内存。
事实上,我在一个问题中问过这种"踩地雷"的行为。
但我不确定它是否会导致错误,或者显式调用析构函数是危险的。打电话给你给我一些建议
您编写的代码有三个主要缺点:
-
读取很困难
-
它针对不常见的情况进行了优化(总是执行自分配检查,尽管在实践中很少执行自分配)
-
它不是例外安全的
考虑使用复制和交换习惯用法:
Student & assign(Student stu) // pass stu by value, constructing temp instance
{ // this is the "copy" part of the idiom
using namespace std;
swap(*this, stu); // pass current values to temp instance to be destroyed
// and temp values to *this
return *this;
} // temp goes out of scope thereby destroying previous value of *this
如果交换不抛出,这种方法是异常安全的,并且它有两个潜在的缺点:
如果Student是类层次结构的一部分(具有虚拟成员),则创建临时实例的成本将更高。
在自分配的情况下,实现应该是no-op(或自相等测试),但在这种情况下,它将创建一个额外的对象实例。自我分配的情况非常罕见。
您的建议是一个主要的反模式:如果new
终止除了一个例外,你会得到未定义的行为,如果有人试图从你的课堂上派生出各种奇怪的东西发生:
DerivedStudent a;
DerivedStudent b;
a = b; // Destructs a, and reconstructs it as a Student
当a
超出作用域时,它是的析构函数将被调用的CCD_ 3。
一般来说,如果你必须测试自我分配赋值运算符不是异常安全的。
当然,这个习语的目的是避免代码重复在复制构造函数和赋值运算符之间,以及确保它们具有相同的语义。一般来说,最好的这样做的方法是使用交换习惯用法,或者类似的东西:
Student&
Student::operator=( Student const& other )
{
Student tmp( other );
swap( tmp );
return *this;
}
void
Student::swap( Student& other )
{
myName.swap( other.myName );
std::swap( myAge, other.myAge );
}
(最后一点,无关。在练习中,你要跑与以下划线开头的名称冲突。在里面一般来说,最好避免使用前导或尾随下划线。)
- 给定一个指向堆分配内存的指针,智能指针实现如何为其找到合适的释放函数?
- 未分配被释放的指针(将堆栈实现为链表时)
- 如何有效地实现将向量的数据分配给多个变量?
- 在内存中连续分配的多维数组的实现
- 如何实现,错误分配中止而不是抛出异常
- 有没有办法自动实现 sprintf 的缓冲区分配?
- 我如何实现向量重新分配
- 将模板化实现分配给先前声明的函数
- 在使用表达模板的矩阵库中实现一个行类别的分配运算符
- 实现unique_ptr:删除未分配的对象
- 如何在链接列表类中实现分配运算符
- 为什么完美的转发(全部捕获)不能实现复制分配?
- 了解循环缓冲区实现的内存分配性质
- 如何实现分配器感知的容器分配
- 实现对象列表时,如何处理动态分配
- 复制/移动操作符是否可以安全地用于实现复制/移动分配操作符
- 每次复制实现移动分配的非 const 对象时,我是否总是获得移动语义
- 在C/C 中实现实时最佳拟合内存分配算法
- 如何使用 C++ 实现分配策略
- 一种按'new'实现分配的方法