C++ 如何使用C++;安置新作品?
这个问题是为了确认我正确理解了这个概念,并就使用方式和可能的优化采纳了专家意见 我正在努力理解“新的安置”,下面是我提出的计划C++ 如何使用C++;安置新作品?,c++,placement-new,C++,Placement New,这个问题是为了确认我正确理解了这个概念,并就使用方式和可能的优化采纳了专家意见 我正在努力理解“新的安置”,下面是我提出的计划 #include <iostream> #include <new> class A { int *_a; public: A(int v) {std::cout<<"A c'tor clalled\n";_a= new int(v);} ~A() {std::cout<<"A d'tor clalled\
#include <iostream>
#include <new>
class A {
int *_a;
public:
A(int v) {std::cout<<"A c'tor clalled\n";_a= new int(v);}
~A() {std::cout<<"A d'tor clalled\n"; delete(_a);}
void testFunction() {std::cout<<"I am a test function &_a = "<<_a<<" a = "<<*_a<<"\n";}
};
int main()
{
A *obj1 = new A(21);
std::cout<<"Object allocated at "<<obj1<<std::endl;
obj1->~A();
std::cout<<"Object allocated at "<<obj1<<std::endl;
obj1->testFunction();
A *obj2 = new(obj1) A(22);
obj1->testFunction();
obj2->testFunction();
delete(obj1);// Is it really needed now? Here it will delete both objects.. so this is not the right place.
//obj1->testFunction();
//obj2->testFunction();
return 0;
}
我有以下问题
- 这是演示新位置的正确示例吗
- 成员a是动态分配的(没有新位置)。那么,为什么它会获得与obj1和obj2相同的地址呢。这只是巧合吗李>
- D'tor打15号线电话是一种好的做法吗李>
还请指出,你看到的任何东西,我可以改善或只是不尝试。任何好的参考或阅读都是受欢迎的。这可能是为了,在回答您的问题之前,让我对您的源代码稍加评论
A *obj1 = new A(21);
std::cout<<"Object allocated at "<<obj1<<std::endl;
obj1->~A();
这是UB。您已经破坏了对象,不应该对其调用任何方法
18 A *obj2 = new(obj1) A(22);
19 obj1->testFunction();
20 obj2->testFunction();
虽然obj1
和obj2
是完全相同的对象,但请注意,这是一个okayish
21 delete(obj1);// Is it really needed now? Here it will delete both objects.. so this is not the right place.
你的评论是错误的。你不是在删除两个对象,而是在删除一个,以后还会删除更多
22 obj1->testFunction();
23 obj2->testFunction();
这也是UB,不要对解构或删除的对象调用方法。
关于你的问题:
成员_a是动态分配的(没有新的位置)。那么,为什么obj1和obj2的地址相同呢。这只是巧合吗
不要将它们称为obj1
和obj2
,因为这两个变量指向同一个对象,但是是的,这是巧合。在第一个对象被销毁并释放内存后,第二个对象分配了刚刚释放的相同内存量,分配器决定给您完全相同的内存
D'tor打15号线电话是一种好的做法吗
不,不是。很少有例子说明为什么需要调用析构函数,其中一个例子是对象是通过放置新对象创建的。在您的示例中,这没有副作用,因为在解构旧对象之后,您在同一位置构造了一个新对象,并且新对象与旧对象的类型相同,否则这可能会以某种方式严重损坏
现在,在删除之后,再了解一下您的评论。让我们看看一个新的和一个新的位置实际上做了什么
一种新的方法是:
- 从操作系统为新对象分配内存
- 调用新对象上的构造函数,地址(
)设置为分配器获得的内存块this
- 调用对象的析构函数
- 释放内存块
this
设置为您传递的地址。因此,placement new的反面就是调用析构函数,因为不存在placement delete
这意味着对于代码来说,在调用析构函数后,第一个对象死亡,但您从未归还内存,这就是您可以在该内存中构造新对象的原因。现在,当您调用delete时,第一个对象不再存在,只有它使用的内存,但相同的内存现在被第二个对象阻塞,因此,当您调用delete时,您不删除两个对象,只删除第二个对象(解构它,然后释放内存块)
您可以阅读更多关于主题placement new和何时调用析构函数的信息,它非常非常简单:
new
可以被认为是在做两件事:
malloc
,但通常是这样。您不能假设它是关于实现的,但是为了理解它,这是一个OK的假设
因此,以下内容被认为是等效的:
auto obj1 = new std::string("1");
// ↑ can be thought of as equivalent to ↓
auto obj2 = (std::string*)malloc(sizeof(std::string));
new(obj2) std::string("2");
同样的情况也适用于删除:
delete obj1;
// ↑ can be thought of as equivalent to ↓
obj2->~string();
free(obj2);
然后,当您看到new
和delete
时,您可以很容易地对它们进行推理,了解它们的真正含义:分配之后是构造函数调用,析构函数调用之后是释放
当您使用placementnew
时,您已经决定单独处理第一步。内存仍然必须以某种方式分配,您只需完全控制它是如何发生的以及内存来自何处
因此,您必须分别跟踪两件事:
记忆的生命周期
对象的生存期
下面的代码演示了它们是如何相互独立的:
#include <cstdlib>
#include <string>
#include <new>
using std::string;
int main() {
auto obj = (string*)malloc(sizeof(string)); // memory is allocated
new(obj) string("1"); // string("1") is constructed
obj->~string (); // string("1") is destructed
new(obj) string("2"); // string("2") is constructed
obj->~string (); // string("2") is destructed
free(obj); // memory is deallocated
}
但这没关系:
void ub() {
alignas(string) char buf[sizeof(string)]; // memory is allocated
new(buf) string("1"); // string("1") is constructed
buf->~string(); // string("1") is destructed
} // memory is deallocated
请注意如何使用正确对齐自动缓冲区。对于任意类型,缺少alignas
,会导致UB。它可能看起来有效,但那只会误导你
有一些特定的类型,不调用析构函数和不正确对齐内存不会导致UB,但是您永远不应该假设类型存在这种情况。调用析构函数并进行对齐,如果结果证明不必要,则不会花费任何费用-不会为此类类型生成额外代码
struct S {
char str[10];
}
< C++如何放置新作品?< /P>
我正在努力理解“新的安置”,下面是我提出的计划
#include <iostream>
#include <new>
class A {
int *_a;
public:
A(int v) {std::cout<<"A c'tor clalled\n";_a= new int(v);}
~A() {std::cout<<"A d'tor clalled\n"; delete(_a);}
void testFunction() {std::cout<<"I am a test function &_a = "<<_a<<" a = "<<*_a<<"\n";}
};
int main()
{
A *obj1 = new A(21);
std::cout<<"Object allocated at "<<obj1<<std::endl;
obj1->~A();
std::cout<<"Object allocated at "<<obj1<<std::endl;
obj1->testFunction();
A *obj2 = new(obj1) A(22);
obj1->testFunction();
obj2->testFunction();
delete(obj1);// Is it really needed now? Here it will delete both objects.. so this is not the right place.
//obj1->testFunction();
//obj2->testFunction();
return 0;
}
这两个答案都很好。但你也想知道它是如何工作的,因此,我将补充大会的解释:
A*obj1=新的A(21)代码>:
A*obj2=new(obj1)A(22)代码>
这就是它的工作原理,足够清楚,不需要更多的解释,对吗?更清楚地说,取消引用已被delete
ed调用的指针将调用UB。对于有关行为的问题-是的,正如您所怀疑的那样。第22行和第23行至调用未定义的行为
void ub() {
alignas(string) char buf[sizeof(string)]; // memory is allocated
new(buf) string("1"); // string("1") is constructed
buf->~string(); // string("1") is destructed
} // memory is deallocated
struct S {
char str[10];
}
call operator new(unsigned long)
mov esi, 21
mov rdi, rax
mov rbx, rax
call A::A(int)
mov esi, 22
mov rdi, rbx
call A::A(int)