2012-10-23 55 views
0

我想在不調用構造函數的情況下在堆棧上分配類和數組。下面的例子clarifys:未初始化類的數組

template<class t,int SetNum> class set 
{ 
private: 
    t Storage[SetNum]; 
}; 

class myClass 
{ 
private: 
    int* Array; 
public: 
    myClass() 
    { 
     Array=new int[10]; 
    } 
} 
int main() 
{ 
    set<myClass,10> Set; 
} 

我不想分配10個新的整數時myClass的構造函數被調用時發生Array,但還是要分配給myClass的空間。

+0

問題不明確。你想不要分配myClass數組或int數組嗎? – garbagecollector

+1

創建一個對象數組將自動調用默認的構造函數。沒有辦法避免這種情況。如果你認爲你需要避免調用默認的構造函數,你想做什麼? –

+0

@DumpHole這個問題清楚地指出:「我不想爲'Array的'分配10個新的ints',當'myClass'的構造函數被調用時出現' –

回答

1

你必須具有unsigned char S(或例如)的陣列作爲用於您的元素「備份存儲」來使用,然後調用放置new操作者(例如,參見here)來構建你實例有(其由方式,是什麼std::vector已經做到了)。

警告:如果你使用定位new你有責任手動取消分配你用它創建的對象,明確調用析構函數;同樣,您傳遞給展示位置的指針必須正確地與您正在創建的對象對齊,否則可能會發生不好的事情。請參閱this question。的std::arraystd::vector扭曲混合物與所描述的技術的內置


實施例(需要C++ 11爲union特技工作):

#include <cstddef> 
#include <memory> 
#include <stdexcept> 
#include <iostream> 

template<typename T, std::size_t N> 
class array_noinit 
{ 
    union storage_helper 
    { 
    private: 
     // this member assures that the storage is properly aligned 
     T t; 
    public: 
     unsigned char storage[sizeof(T)*N]; 

     // needed because T's constructor/destructor is implicitly deleted 
     storage_helper() { }; 
     ~storage_helper() { }; 
    }; 

    storage_helper s; 

    std::size_t _size; 
    T * _storage; 
public: 
    array_noinit() : 
     _size(0), _storage((T*)s.storage) 
    {} 

    ~array_noinit() 
    { 
     while(_size>0) 
      pop_back(); 
    } 

    void push_back(const T & elem) 
    { 
     if(_size>=N) 
      throw std::runtime_error("Not enough capacity."); 
     new(_storage+_size) T(elem); 
     _size++; 
    } 

    void pop_back() 
    { 
     if(_size>0) 
     { 
      _size--; 
      _storage[_size].~T(); 
     } 
    } 

    T & at(std::size_t Idx) 
    { 
     if(Idx>=_size) 
      throw std::out_of_range("Idx out of range."); 
     return _storage[Idx]; 
    } 

    std::size_t size() const 
    { 
     return _size; 
    } 

    std::size_t capacity() const 
    { 
     return N; 
    } 
}; 

class A 
{ 
    int _i; 
public: 
    A(int i) : _i(i) 
    { 
     std::cout<<"In A constructor - "<<_i<<"\n"; 
    } 

    A(const A & right) 
     : _i(right._i) 
    { 
     std::cout<<"In A copy constructor - "<<_i<<"\n"; 
    } 

    ~A() 
    { 
     std::cout<<"In A destructor - "<<_i<<"\n"; 
    } 
}; 

int main() 
{ 
    std::cout<<"With ints\n"; 
    array_noinit<int, 4> arr; 
    arr.push_back(1); 
    arr.push_back(2); 
    arr.push_back(3); 
    arr.push_back(4); 

    for(std::size_t i=0; i<4; i++) 
     std::cout<<arr.at(i)<<" "; 
    std::cout<<"\n"; 

    std::cout<<"With a class - we don't add anything\n"; 
    array_noinit<A, 10> arr2; 

    std::cout<<"With a class - now we add stuff\n"; 
    array_noinit<A, 10> arr3; 
    arr3.push_back(A(1)); 
    arr3.push_back(A(2)); 
    arr3.push_back(A(3)); 
    return 0; 
} 

輸出:

With ints 
1 2 3 4 
With a class - we don't add anything 
With a class - now we add stuff 
In A constructor - 1 
In A copy constructor - 1 
In A destructor - 1 
In A constructor - 2 
In A copy constructor - 2 
In A destructor - 2 
In A constructor - 3 
In A copy constructor - 3 
In A destructor - 3 
In A destructor - 3 
In A destructor - 2 
In A destructor - 1 

Edi t有一個much simpler way to get aligned storage

+0

你對齊的意思是什麼? – Lauer

+0

並非每個對象都可以放在任何地址上,有些地址可以放置地址(例如,在某些平臺上,32位整數只能保留在4字節的多個地址上)。爲了解決這類問題,我將「後備存儲」sizeof(t)放大到比所需要的大,然後使用'alignof'運算符/'align'函數確定實際使用的第一個地址作爲存儲't'類型的對象。 –

+0

......實際上,你可以使用另一個技巧:你的「後備存儲器」可以保留在一個'union'中,它有一個't'類型的單元,它不會自動構造/破壞(C++ 11,[class .union]¶2-4),但保證它作爲一個整體與你的類型't'正確對齊。 –