c++中new的用法


new operator

  內置的new操作符,經常使用的T *ptr = new T(),分配內存,調用構造函數

  1. 調用operator new分配內存,operator new (sizeof(A)) 
  2. 調用構造函數生成類對象,A::A() ,調用placement new
  3. 返回相應指針 

  事實上,分配內存這一操作就是由operator new(size_t)來完成的,如果類A重載了operator new,那么將調用A::operator new(size_t ),否則調用全局::operator new(size_t ),后者由C++默認提供。

operator new

  像普通運算符一樣可以被重載,operator new會去申請內存,申請失敗的時候會調用new_handler處理,這是一個循環的過程,如果new_handler不拋出異常,會一直循環申請內存,直到成功。

(1) void* operator new (std::size_t size);
(2) void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) noexcept;
(3) void* operator new (std::size_t size, void* ptr) noexcept;
  1. 分配size字節的存儲空間,如果成功的話返回一個非空指針,將對象類型進行內存對齊,指向分配空間第一個字節。如果失敗的話,會拋出bad_alloc異常,不調用構造函數
  2. 和第一種一樣,差別在於,如果失敗的話,不拋出異常,而是返回一個null指針,不調用構造函數
  3. 只是返回ptr指針,並不分配內存空間。這里的ptr應該指向先前已經分配好的空間,這里的new調用對象的構造函數,在ptr指向的內存空間構造對象或對象數組。ptr指向的內存只要不釋放,可以重復使用,所以這種用法一般在對象池或內存池實現中使用也就是placement new版本
#include <iostream>
#include <new>
using namespace std;

struct A
{
    A( bool xpt )
    {
        if( xpt )
            throw( xpt );
    }

    void *operator new(size_t size)
    {
        cout<<"operator new"<<endl;
        return malloc(size);
    }
    void operator delete(void *p)
    {
        cout<<"operator delete"<<endl;
        free(p);
    }
  

    void *operator new(size_t size,const nothrow_t &thorw_value) noexcept
    {
        cout<<"operator new noexcept"<<endl;
        return malloc(size);
    }
    void operator delete(void *p,const nothrow_t &nowthrow_value) throw()
    {
        cout<<"operator delete noexpect."<<endl;
        free(p);
    }
};

int main()
{
    A* a1 = new A(false);
    delete a1;

    try 
    {    
        A* a2 = new A(true);
        delete a2;
    }
    catch( ... )
    {
        // 
    }
  

    A* a3 = new(nothrow) A(false);
    delete a3;

    try 
    {
        A* a4 = new(nothrow) A(true);
        delete a4;
    }
    catch( ... )
    {
        
    }
    return 0;
}

在分配失敗的情況下,拋出異常std::bad_alloc而不是返回NULL,因此通過判斷返回值是否為NULL是徒勞的。

placement new

  除了應該有的size_t size參數,多其他的任何參數都可以看做placement new

  1. 這種new允許在一塊已經分配成功的內存上重新構造對象或對象數組。placement new不用擔心內存分配失敗,因為它根本不分配內存,它做的唯一一件事情就是調用對象的構造函數
  2. 用定位放置new操作,既可以在棧(stack)上生成對象,也可以在堆(heap)上生成對象。
  3. 使用語句A* p=new (mem) A;定位生成對象時,指針p和數組名mem指向同一片存儲區。 會自動調用類A的構造函數,但是由於對象的空間不會自動釋放(對象實際上是借用別人的空間),所以必須顯示的調用類的析構函數,如本例中的p->~A()。 
void* operator new (std::size_t size, void* ptr) noexcept;

  placement new構造起來的對象或其數組,要顯示的調用他們的析構函數來銷毀,千萬不要使用delete ,要顯式調用它們的析構函數來銷毀(析構函數並不釋放對象的內存,這是因為placement new構造起來的對象或數組大小並不一定等於原來分配的內存大小,使用delete會造成內存泄漏或者之后釋放內存時出現運行時錯誤。

#include <iostream>
#include <new>
#include <cstdio>
using namespace std;

struct A
{
    char c;
    int i;
    short a;
}; 

int main()
{
    A *a1=new A;
    A *a2=new(a1) A;//再堆上構造對象
    
    char *c={"fdsafk"};//在棧上構造對象 
    cout<<(void *)c<<endl;
    
    A *a3=new(c) A;
    cout<<a3<<endl;
    return 0;
}

  當使用new運算符定義一個多維數組變量或數組對象時,它產生一個指向數組第一個元素的指針,返回的類型保持了除最左邊維數外的所有維數。例如:  

 int *p1 = new int[10];   

  返回的是一個指向int的指針int*  

int (*p2)[10] = new int[2][10]; 

  new了一個二維數組, 去掉最左邊那一維[2], 剩下int[10], 所以返回的是一個指向int[10]這種一維數組的指針int (*)[10].  

  int (*p3)[2][10] = new int[5][2][10];  new了一個三維數組, 去掉最左邊那一維[5], 還有int[2][10], 所以返回的是一個指向二維數組int[2][10]這種類型的指針int (*)[2][10].     

#include<iostream>
#include <typeinfo> 
using namespace std;

int main() 
{ 
    int *a = new int[34]; 
    int *b = new int[]; 
    int (*c)[2]=new int[][2];//指針 
    
    int[34][2]; 
    int (*d)[2] = new int[][2]; //指針 
    int (*e)[2][3] = new int[34][2][3];
    int (*f)[2][3] = new int[][2][3];//指針 
    
    a[0] = 1; 
    b[0] = 1; //運行時錯誤,無分配的內存,b只起指針的作用,用來指向相應的數據
    c[0][0] = 1;
    d[0][0] = 1;//運行時錯誤,無分配的內存,d只起指針的作用,用來指向相應的數據 
    e[0][0][0] = 1; 
    f[0][0][0] = 1;//運行時錯誤,無分配的內存,f只起指針的作用,用來指向相應的數據 

    cout<<typeid(a).name()<<endl;
    cout<<typeid(b).name()<<endl;
    cout<<typeid(c).name()<<endl; 
    cout<<typeid(d).name()<<endl; 
    cout<<typeid(e).name()<<endl;
    cout<<typeid(f).name()<<endl; 
    delete[] a; 
    delete[] b; 
    delete[] c; 
    delete[] d; 
    delete[] e; 
    delete[] f; 
    return 0;
}   
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM