如何C ++放置新的作品? [英] How C++ placement new works?

查看:192
本文介绍了如何C ++放置新的作品?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是为了确认我理解了这个概念,并就使用风格和可能的优化问题征求专家意见。



我想了解placement new以下是我想出的程序...

  1 #include< iostream> 
2 #include< new>
3
4 A类{
5 int * _a;
6 public:
7(int v){std :: cout<<A c'tor clalled\\\
; _ a = new int(v);}
8 〜A(){std :: cout<<A d'tor clalled\ n; delete(_a);}
9 void testFunction(){std :: cout<<我是一个测试函数& _a =<< _a<<a =< * _a<<\\\
;}
10};
11 int main()
12 {
13 A * obj1 = new A(21);
14 std :: cout<<对象分配在<<< obj1<< std :: endl;
15 obj1->〜A();
16 std :: cout<<对象分配在<<< obj1<< std :: endl;
17 obj1-> testFunction();
18 A * obj2 = new(obj1)A(22);
19 obj1-> testFunction();
20 ob​​j2-> testFunction();
21 delete(obj1); //现在真的需要吗?这里它将删除两个对象..所以这是不正确的地方。
22 // obj1-> testFunction();
23 // obj2-> testFunction();
24 return 0;
25}



当我运行这个程序时,我得到以下o / p

  A c'tor clalled 
分配给0x7f83eb404c30的对象
已分配的
分配给0x7f83eb404c30的对象
我是一个测试函数& _a = 0x7f83eb404c40 a = 21
a c'tor clalled
我是一个测试函数& _a = 0x7f83eb404c40 a = 22
我是一个测试函数& _a = 0x7f83eb404c40 a = 22
已结束
我是一个测试函数& _a = 0x7f83eb404c40 a = 0
我是一个测试函数& _a = 0x7f83eb404c40 a = 0

我有以下问题...


$ b b

  • 这是一个正确的示例来演示展示位置新动态吗?

  • 成员_a是动态分配的所以为什么它得到相同的地址obj1& obj2。这只是一个巧合吗?

  • 是第15行的拨打电话好的做法吗?



请指出您看到的任何我可以改进或只是不尝试的东西。

解决方案



感谢
Vikrant

div>

这真的很简单: new 可以被认为是做两件事:


  1. 分配内存。

  2. 在分配的内存中放置对象。


$ b b

不能保证 malloc 实际上被实现使用,但通常是。



因此,以下被认为是等效的:

  auto obj1 = new std :: string(1); 

auto obj2 =(std :: string *)malloc(sizeof(std :: string));
new(obj2)std :: string(2);

同样适用

  delete obj1; 

obj2->〜std :: string();
free(obj2);

然后,当您看到 new delete ,它们的真正意义是:构造函数调用后的分配,以及释放后的析构函数调用。



当您使用 new 时,您已决定单独处理第一步。



因此,你必须分别跟踪两件事情,分别是:


  • 对象的生命周期。


  • 下面的代码演示了如何独立于彼此:

     #include< cstdlib> 
    #include< string>
    #include< new>

    使用std :: string;

    int main(){
    auto obj =(string *)malloc(sizeof(string)); //内存分配
    new(obj)string(1); // string(1)被构造
    obj->〜string(); // string(1)is destructed
    new(obj)string(2); // string(2)被构造
    obj->〜string(); // string(2)is destructed
    free(obj); // memory is deallocated
    }

    如果对象的生命周期延长,过去的记忆的生命。确保内存始终的寿命比对象的寿命。例如,这是UB:

      void ub(){
    alignas(string)char buf [sizeof )]; //内存已分配
    new(buf)string(1); // string(1)被构造
    } //内存被释放,但字符串(1)比内存更多!

    但这是有效的:

      void ub(){
    alignas(string)char buf [sizeof(string)]; //内存已分配
    new(buf)string(1); // string(1)
    buf->〜string(); // string(1)is destructed
    } //内存被释放

    注意如何使用 alignas 来正确对齐自动缓冲区, a>。对于任意类型,缺少 alignas 会导致UB。它可能似乎工作,但这只是误导你。



    有一些特定的类型,不调用析构函数,没有正确对齐内存不导致UB,但你不应该假设一个类型的这样的事情。调用你的析构函数并做对齐,它不会花费任何东西,如果事实证明是不必要的 - 不会产生这样的类型的额外的代码。

      struct S {
    char str [10];
    }


    This question is to confirm I understood the concept right and take expert opinion on style of usages and possible optimization.

    I am trying to understand "placement new" and following is the program I came up with...

     1  #include <iostream>
     2  #include <new>
     3
     4  class A {
     5    int *_a;
     6    public:
     7      A(int v) {std::cout<<"A c'tor clalled\n";_a= new int(v);}
     8      ~A() {std::cout<<"A d'tor clalled\n"; delete(_a);}
     9      void testFunction() {std::cout<<"I am a test function &_a = "<<_a<<" a = "<<*_a<<"\n";}
    10  };
    11  int main()
    12  {
    13    A *obj1 = new A(21);
    14    std::cout<<"Object allocated at "<<obj1<<std::endl;
    15    obj1->~A();
    16    std::cout<<"Object allocated at "<<obj1<<std::endl;
    17    obj1->testFunction();
    18    A *obj2 = new(obj1) A(22);
    19    obj1->testFunction();
    20    obj2->testFunction();
    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();
    24    return 0;
    25  }
    

    When I run this program I get following o/p

    A c'tor clalled
    Object allocated at 0x7f83eb404c30
    A d'tor clalled
    Object allocated at 0x7f83eb404c30
    I am a test function &_a = 0x7f83eb404c40 a = 21
    A c'tor clalled
    I am a test function &_a = 0x7f83eb404c40 a = 22
    I am a test function &_a = 0x7f83eb404c40 a = 22
    A d'tor clalled
    I am a test function &_a = 0x7f83eb404c40 a = 0
    I am a test function &_a = 0x7f83eb404c40 a = 0
    

    I have following question...

    • Is it a correct example to demonstrate placement new?
    • member _a is dynamically allocated (with no placement new). So why it is getting same same address for obj1 & obj2. Is it just a coincidence?
    • is D'tor call on line 15 a good practice?

    Please also point out of you see any thing which I can improve on or just do not try. Any good reference or reads are also welcome.

    Thanks Vikrant

    解决方案

    It's really, really simple: new can be thought of as doing two things:

    1. Allocating the memory.
    2. Placement-constructing the object in the allocated memory.

    There's no guarantee that malloc is actually used by the implementation, but typically it is. You cannot assume it about the implementation, but for the purpose of understanding it's an OK assumption.

    Thus, the following are thought of as being equivalent:

    auto obj1 = new std::string("1");
    
    auto obj2 = (std::string*)malloc(sizeof(std::string));
    new(obj2) std::string("2");
    

    Same goes for delete:

    delete obj1;
    
    obj2->~std::string();
    free(obj2);
    

    You can then easily reason about it all when you see new and delete for what they really are: an allocation followed by constructor call, and a destructor call followed by deallocation.

    When you use placement new, you've decided to take care of the first step separately. The allocation must still happen, you just get to have full control over how it happens and where does the memory come from.

    You thus must keep track of two things, separately:

    1. The lifetime of the memory.

    2. The lifetime of the object.

    The code below demonstrates how these are independent of each other:

    #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
    }
    

    Your program inovkes UB if the lifetime of the object extends past the lifetime of memory. Make sure that the memory always outlives the life of the object. For example, this is UB:

    void ub() {
        alignas(string) char buf[sizeof(string)]; // memory is allocated
        new(buf) string("1");                     // string("1") is constructed
    } // memory is deallocated but string("1") outlives the memory!
    

    But this is valid:

    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
    

    Note how you need to properly align the automatic buffer using alignas. The lack of alignas for an arbitrary type results in UB. It might appear to work, but that's only to mislead you.

    There are some specific types where not calling the destructor and not aligning the memory properly does not lead to UB, but you should never assume such things about a type. Call your destructors and do the alignment, it won't cost you anything if it turns out to be unnecessary - no extra code would be generated for such a type.

    struct S {
      char str[10];
    }
    

    这篇关于如何C ++放置新的作品?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆