2017-05-14 91 views
3

考慮我有一個沒有公共構造函數的類,而是一個靜態工廠或構建器方法,並且創建的對象的大小取決於傳遞給工廠的參數(或建設者)。C++ 11智能指針爲變量大小的對象做功能

有沒有辦法使用std::make_shared(或std::make_unique)創建一個這樣的對象的共享(或唯一)指針?

對於任何建議的多態性,我比較喜歡虛擬方法的模板。

+1

你是什麼意思的「大小」的對象?您不能擁有大小不同的相同類的實例。 – Quentin

+0

「大小」是構建對象時分配的連續內存的字節長度,當它被銷燬時釋放。 –

+0

你能編輯一些代碼,顯示你如何創建這些對象*沒有*智能指針? – Quentin

回答

3

考慮我有一個類沒有公共構造...

有沒有一種方法來創建一個使用std::make_shared(或std::make_unique)的共享(或唯一的)指向這樣一個對象?

有沒有這樣的方式。 std::make_sharedstd::make_unique需要公共構造函數。

相反,你可以創建一個沒有便利的 「make」 功能共享的(唯一的)指針:

// within the factory 
return std::shared_ptr<T>(new T(size)); 

PS。 C++ 11標準庫沒有std::make_unique

-1
#include <memory> 
#include <vector> 
#include <iostream> 

template <typename T> 
std::unique_ptr<T> buildObjectWithSize(std::size_t size) { 
    return std::unique_ptr<T>{T::buildObject(size)}; 
} 

class MyObject { 
public: 
    static MyObject* buildObject(std::size_t size) { 
     return new MyObject(size); 
    } 

    int& operator[](int i) { 
     return int_vector[i]; 
    } 
private: 
    MyObject(std::size_t size) 
    : int_vector(size) { 
    } 

    std::vector<int> int_vector; 
}; 

int main() { 
    constexpr unsigned INT_VECTOR_SIZE{3U}; 

    std::unique_ptr<MyObject> my_object_up{buildObjectWithSize<MyObject>(INT_VECTOR_SIZE)}; 

    (*my_object_up.get())[1] = 5; 
    std::cout << (*my_object_up.get())[1] << '\n'; 

    MyObject &my_object_ref = *my_object_up.get(); 
    my_object_ref[2] = 3; 
    std::cout << my_object_ref[2] << '\n'; 
} 
2

如果你有一個就地工廠方法,將構造對象在你提供給它的內存塊,加,告訴你你需要多少空間的方法,你可以做到這一點。

如果您確實需要C++ 11,我將自由使用C++ 14,添加您自己的typename::type

首先,我們假定我們有這樣的:

struct some_args { 
    // whatever 
}; 
std::size_t how_big_is_X(some_args); 
X* make_X(some_args, void* buffer); 

上述,我可以做一些功能上等同於make_shared

template<std::size_t Sz, std::size_t align=alignof(void*)> 
struct smart_buffer_t { 
    void(*dtor)(void*) = 0; 
    std::aligned_storage_t< Sz, align> data; 
    template<class T, class...Args> 
    T* emplace(Args&&...args) { 
    return ctor([&](void* pdata) { 
     ::new(pdata) T(std::forward<Args>(args)...); 
    }); 
    } 
    template<class F> 
    T* ctor(F&& f) { 
    std::forward<F>(f)((void*)&data); 
    dtor = [](void* ptr){ 
     static_cast<T*>(ptr)->~T(); 
    }; 
    return static_cast<T*>((void*)&data); 
    } 
    ~smart_buffer_t() { 
    if (dtor) dtor(&data); 
    } 
}; 

template<class T, std::size_t Sz, std::size_t Algn=alignof(void*), class F> 
std::shared_ptr<T> 
make_sized(F&& f) { 
    auto pbuff = std::make_shared<smart_buffer_t<Sz, Algn>>(); 
    T* r = pbuff->ctor(std::forward<F>(f)); 
    return {r, pbuff}; // aliasing ctor 
} 

現在我們有:

template<std::size_t I> 
using index_t = std::integral_constant<std::size_t, I>; 
template<std::size_t I> 
using pow_t = index_t< (1<<I) >; 

std::shared_ptr<X> 
make_shared_X(some_args args) { 
    std::size_t Sz = how_big_is_X(args); 
    using pmaker = std::shared_ptr<X>(*)(some_args); 
    using maker_maker = [](auto Sz){ 
    return +[](some_args args) { 
     return make_sized<X, Sz>([&](void* ptr){ 
     return make_X(args, ptr); 
     }); 
    }; 
    }; 
    static const pmaker table[] = { 
    maker_maker(pow_t<0>{}), 
    maker_maker(pow_t<1>{}), 
    maker_maker(pow_t<2>{}), 
    // ... 
    maker_maker(pow_t<63>{}), // assuming 64 bit size_t. 
    }; 
    std::size_t i = 0; 
    while(Sz > (1<<i)) 
    ++i; 
    return table[i](args); 
} 

或諸如此類。

未經測試的代碼。它分配的權力等於或大於你的參數需求。但是該對象的構造與引用計數塊的分配相同。

可以使用任何系列而不是2的冪數,但表格大小必須足夠大以處理來自how_big_is_X的最大可能返回值。