这个问题是要确认我理解概念正确,并就使用方式和可能的优化采取专家意见。

我正在尝试理解“新的刊​​登位置”,以下是我想出的程序...

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

当我运行该程序时,我会跟随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

我有以下问题...
  • 演示新的展示位置是否正确?
  • 成员a是动态分配的(没有新的位置)。那么为什么它要为obj1和obj2获取相同的地址。只是巧合吗?
  • 是D'tor在第15行打电话的好习惯吗?

  • 还请指出您看到的任何我可以改进的地方,或者就是不要尝试。也欢迎任何好的引用或阅读。

    最佳答案

    这非常非常简单:new可以看作是做两件事:

  • 分配内存。
  • 将对象放置在分配的内存中。

  • 无法保证实现确实使用了malloc,但通常情况下确实如此。您不能假设它是关于实现的,但是出于理解的目的,这是一个好的假设。
    因此,以下内容被认为是等效的:
    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也是如此:
    delete obj1;
    // ↑ can be thought of as equivalent to ↓
    obj2->~string();
    free(obj2);
    
    然后,当您看到newdelete的真正含义时,可以很容易地对此进行推理:分配之后是构造函数调用,而析构函数调用之后是释放。
    当您使用new放置时,您已经决定分别进行第一步。必须仍然以某种方式分配内存,您才可以完全控制内存的发生方式以及内存来自何处。
    因此,您必须分别跟踪两件事:
  • 内存的生存期。
  • 对象的生存期。

  • 下面的代码演示了它们如何彼此独立:
    #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
    }
    
    如果对象的生存期超过了内存的生存期,则您的程序将具有UB。确保内存始终超过对象的生命周期。例如,这具有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!
    
    但这没关系:
    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 正确对齐自动缓冲区。任意类型缺少alignas都会导致UB。它可能看起来有效,但这只是在误导您。
    在某些特定类型中,不调用析构函数且未正确对齐内存不会导致UB,但是您永远都不应假设这种类型。调用析构函数并进行对齐,如果事实证明这是不必要的,则不会花费您任何费用-这种类型的代码不会生成任何额外的代码。
    struct S {
      char str[10];
    }
    

    关于c++ - C++放置新功能如何工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35087204/

    10-09 06:32
    查看更多