2017-05-14 96 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的最大可能返回值。