I'm interested in building an uninitialized_vector container, which will be semantically identical to std::vector with the caveat that new elements which otherwise would be created with a no-argument constructor will instead be created without initialization. I'm primarily interested in avoiding initializing POD to 0. As far as I can tell, there's no way to accomplish this by combining std::vector with a special kind of allocator.
I'd like to build my container in the same vein as std::stack, which adapts a user-provided container (in my case, std::vector). In other words, I'd like to avoid reimplementing the entirety of std::vector and instead provide a "facade" around it.
Is there a simple way to control default construction from the "outside" of std::vector?
Here's the solution I arrived at, which was inspired Kerrek's answer:
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <cassert>
// uninitialized_allocator adapts a given base allocator
// uninitialized_allocator's behavior is equivalent to the base
// except for its no-argument construct function, which is a no-op
template<typename T, typename BaseAllocator = std::allocator<T>>
struct uninitialized_allocator
: BaseAllocator::template rebind<T>::other
{
typedef typename BaseAllocator::template rebind<T>::other super_t;
template<typename U>
struct rebind
{
typedef uninitialized_allocator<U, BaseAllocator> other;
};
// XXX for testing purposes
typename super_t::pointer allocate(typename super_t::size_type n)
{
auto result = super_t::allocate(n);
// fill result with 13 so we can check afterwards that
// the result was not default-constructed
std::fill(result, result + n, 13);
return result;
}
// catch default-construction
void construct(T *p)
{
// no-op
}
// forward everything else with at least one argument to the base
template<typename Arg1, typename... Args>
void construct(T* p, Arg1 &&arg1, Args&&... args)
{
super_t::construct(p, std::forward<Arg1>(arg1), std::forward<Args>(args)...);
}
};
namespace std
{
// XXX specialize allocator_traits
// this shouldn't be necessary, but clang++ 2.7 + libc++ has trouble
// recognizing that uninitialized_allocator<T> has a well-formed
// construct function
template<typename T>
struct allocator_traits<uninitialized_allocator<T> >
: std::allocator_traits<std::allocator<T>>
{
typedef uninitialized_allocator<T> allocator_type;
// for testing purposes, forward allocate through
static typename allocator_type::pointer allocate(allocator_type &a, typename allocator_type::size_type n)
{
return a.allocate(n);
}
template<typename... Args>
static void construct(allocator_type &a, T* ptr, Args&&... args)
{
a.construct(ptr, std::forward<Args>(args)...);
};
};
}
// uninitialized_vector is implemented by adapting an allocator and
// inheriting from std::vector
// a template alias would be another possiblity
// XXX does not compile with clang++ 2.9
//template<typename T, typename BaseAllocator>
//using uninitialized_vector = std::vector<T, uninitialized_allocator<T,BaseAllocator>>;
template<typename T, typename BaseAllocator = std::allocator<T>>
struct uninitialized_vector
: std::vector<T, uninitialized_allocator<T,BaseAllocator>>
{};
int main()
{
uninitialized_vector<int> vec;
vec.resize(10);
// everything should be 13
assert(std::count(vec.begin(), vec.end(), 13) == vec.size());
// copy construction should be preserved
vec.push_back(7);
assert(7 == vec.back());
return 0;
}
This solution will work depending on how closely a particular vendor's compiler & STL's std::vector implementation conforms to c++11.
Instead of using a wrapper around the container, consider using a wrapper around the element type:
template <typename T>
struct uninitialized
{
uninitialized() { }
T value;
};
I think the problem boils down to the type of initialization that the container performs on elements. Compare:
T * p1 = new T; // default-initalization
T * p2 = new T(); // value-initialization
The problem with the standard containers is that they take the default argument to be value initialized, as in resize(size_t, T = T()). This means that there's no elegant way to avoid value-initialization or copying. (Similarly for the constructor.)
Even using the standard allocators doesn't work, because their central construct() function takes an argument that becomes value-initialized. What you would rather need is a construct() that uses default-initialization:
template <typename T>
void definit_construct(void * addr)
{
new (addr) T; // default-initialization
}
Such a thing wouldn't be a conforming standard allocator any more, but you could build your own container around that idea.
I don't believe this is possible by wrapping a vector (that works with every type), unless you resize the vector on every add and remove operation.
If you could give up wrapping STL containers, you could do this by keeping an array of char on the heap and using placement new for each of the objects you want to construct. This way you could control exactly when the constructors and destructors of objects were called, one by one.
Related
I have a function that creates a new object of the underlying type of P. Here P is a dereferencable type like a pointer or a smart pointer.
template<typename P>
auto make_new()
For example, for pointers and smart pointers,
struct A
{
int a = 3;
};
A* a = make_new<A*>();
std::cout << a->a << std::endl;
delete a;
std::shared_ptr<A> b = make_new<std::shared_ptr<A>>();
std::cout << b->a << std::endl;
Now, for shared pointers, I would implement make_new as the following,
template<typename P>
auto make_new()
{
using Ptype = typename P::element_type;
return P(new Ptype);
}
which doesn't work for pointers.
Now, something that works for both pointers and smart pointers,
template<typename P>
auto make_new()
{
using Ptype = typename std::remove_reference<decltype(*P())>::type;
return P(new Ptype);
}
but doesn't work for std::optional.
Is there a canonical way of getting the underlying type of a de-referencable object?
I know that * and -> can be overloaded to anything and there is no guarantee that constructor works like above, or makes sense to do.
Just want to know if there is a way and am not just finding it, or just doing something dumb.
Resolving the element type on both pointers and classes
Target. Our goal is to write a using template which takes a dereference-able type as input, and returns the element type.
template<class T>
using element_type_t = /* stuff */;
Method. We can use SFINAE to check if there's an element_type property, and if there's not, we fall back to using std::remove_reference<decltype(*P())>().
// This is fine to use in an unevaluated context
template<class T>
T& reference_to();
// This one is the preferred one
template<class Container>
auto element_type(int)
-> typename Container::element_type;
// This one is the fallback if the preferred one doesn't work
template<class Container>
auto element_type(short)
-> typename std::remove_reference<decltype(*reference_to<Container>())>::type;
Once we have this function, we can write element_type_t by just getting the return type of element_type.
// We alias the return type
template<class T>
using element_type_t = decltype(element_type<T>(0));
Why can't we always get the element_type by dereferencing it? If you try to always get the value type using the * operator, that could cause issues with things like the iterator for std::vector<bool>, which returns an object that acts like a bool, but encapsulates bit manipulations. In these cases, the element type is different than the type returned by dereferencing it.
Determining if the constructor takes a pointer or a value
The reason your code fails with std::optional is because std::optional's constructor takes the value itself, rather than a pointer to the value.
In order to determine which constructor we need, we use SFINAE again to make the determination.
// Base case - use new operator
template<class Container>
auto make_new_impl(int)
-> decltype(Container{new element_type_t<Container>})
{
return Container{new element_type_t<Container>};
}
// Fallback case, where Container takes a value
template<class Container>
auto make_new_impl(long)
-> decltype(Container{element_type_t<Container>()})
{
return Container{element_type_t<Container>()};
}
Now, we can write make_new so that it calls make_new_impl:
template<class Container>
auto make_new() {
return make_new_impl<Container>(0);
}
Example. We can now use make_new to make either std::optional, std::shared_ptr, or even a regular pointer.
#include <optional>
#include <memory>
int main() {
// This works
int* ptr = make_new<int*>();
// This works too
std::shared_ptr<int> s = make_new<std::shared_ptr<int>>();
// This also works
std::optional<int> o = make_new<std::optional<int>>();
}
Is there a convenient way to re-assign the value of a unique_ptr with a new owned object, without re-specifying the type?
For instance:
std::unique_ptr<int> foo;
// .... Later, once we actually have a value to store...
foo = std::make_unique<int>(my_cool_value);
Of course int is not too much of an eyesore, but foo::element_type could be long or subject to change after a refactoring.
So, to use type inference, we could do:
foo = std::make_unique<decltype(foo)::element_type>(value);
...But that's pretty hideous (foo::element_type doesn't work because foo can't be used in a constant expression).
Ideally, std::unique_ptr would support a forwarding emplace-like method:
foo.reassign(value);
This would release the old value and, just like std::vector::emplace, construct the new owned object in-place.
....But as far as I can tell, there's nothing more concise than make_unique<decltype(foo)::element_type>.
EDIT: The most concise way to reassign the value for a type that supports operator= is, of course, to use operator=:
*foo = value;`
...But I do not want to rely on the copyability of element_type (for instance, I initially ran into this issue when trying to work with input-file streams).
Stash the arguments (or references thereto) into a proxy object with a templated conversion operator that deduces the target type. Then construct the new object once you have that deduced.
template<class... Args>
struct maker {
template<class T>
operator std::unique_ptr<T>() && {
return make<T>(std::index_sequence_for<Args...>());
}
std::tuple<Args...> args;
private:
template<class T, size_t ... Is>
std::unique_ptr<T> make(std::index_sequence<Is...>) {
return std::make_unique<T>(std::get<Is>(std::move(args))...);
}
};
template<class... Args>
auto maybe_make_unique_eventually(Args&&... args){
return maker<Args&&...>{std::forward_as_tuple(std::forward<Args>(args)...)};
}
It won't be a member function, but a free function could essentially achieve this:
template<typename T, typename D, typename...Args>
void TakeNew(std::unique_ptr<T,D>& up, Args&&... args)
{
up.reset(new T{std::forward<Args>(args)...});
// or use parentheses for consistency with `make_unique`; see comments
}
// usage...
auto foo = std::make_unique<int>(3);
// .... Later...
TakeNew(foo, 5);
(I do not consider this solution ideal.)
#include <memory>
// a class with a long and unweildy name
namespace mary {
namespace poppins {
struct supercalafragalisticexpialadocious
{
};
}
}
int main()
{
// what we don't want to have to do:
auto a = std::make_unique<mary::poppins::supercalafragalisticexpialadocious>();
// so alias the typename
using atrocious = mary::poppins::supercalafragalisticexpialadocious;
// same type with a shorter name
a = std::make_unique<atrocious>();
}
As you have unique ownership, unless the type is not copyable, you may simply do
*foo = value;
I try to construct a vector with unique_ptr. But I do not find a direct way. The following code does not compiles. The error is:Call to implicitly-deleted copy constructor of 'std::__1::unique_ptr >':
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
class test1{
public:
test1(){};
test1(test1&&)=default;
};
int main(int argc, const char * argv[]) {
std::unique_ptr<test1> us(new test1());
std::vector<std::unique_ptr<test1>> vec{move(us)};
return 0;
}
This make_vector is a function that takes any number of arguments, and perfect-forwards them into a vector.
// get the first type in a pack, if it exists:
template<class...Ts>
struct first {};
template<class T, class...Ts>
struct first<T,Ts...>{
using type=T;
};
template<class...Ts>
using first_t=typename first<Ts...>::type;
// build the return type:
template<class T0, class...Ts>
using vector_T =
typename std::conditional<
std::is_same<T0, void>::value,
typename std::decay<first_t<Ts...>>::type,
T0
>::type;
template<class T0, class...Ts>
using vector_t = std::vector< vector_T<T0, Ts...> >;
// make a vector, non-empty arg case:
template<class T0=void, class...Ts, class R=vector_t<T0, Ts...>>
R make_vector( Ts&&...ts ) {
R retval;
retval.reserve(sizeof...(Ts)); // we know how many elements
// array unpacking trick:
using discard = int[];
(void)discard{0,((
retval.emplace_back( std::forward<Ts>(ts) )
),void(),0)...};
return retval; // NRVO!
}
// the empty overload:
template<class T>
std::vector<T> make_vector() {
return {};
}
use:
std::vector<std::unique_ptr<test1>> vec =
make_vector(
std::move(u1), std::move(u2)
);
live example
I polished it a bit. It will deduce the return type if you pass it 1 or more args and you don't pass it a type. If you pass it a type, it will use that type. If you fail to pass it a type or any args, it will complain. (if you forward packs, or are storing it in a particular type, I'd always give it a type).
A further step could be done, where we do return type deduction to eliminate the requirement to specify the type even in the empty case. This may be required in your use case, I don't know, but it matches how you don't need to specify the type of a {}, so I thought I'd toss it out there:
template<class...Ts>
struct make_vec_later {
std::tuple<Ts...> args; // could make this `Ts&&...`, but that is scary
// make this && in C++14
template<class T, size_t...Is>
std::vector<T> get(std::index_sequence<Is...>) {
return make_vector<T>(std::get<Is>(std::move(args))...);
}
// make this && in C++14
template<class T>
operator std::vector<T>(){
return std::move(*this).template get<T>( std::index_sequence_for<Ts...>{} );
}
};
template<class...Ts>
make_vec_later<Ts...> v(Ts&&...ts) {
return {std::tuple<Ts...>(std::forward<Ts>(ts)...)};
}
this does rely on a C++14 feature of index_sequence, but those are easy to rewrite in C++11 if your compiler doesn't have it yet. Simply google it on stack overflow, there are a myriad of implementations.
Now the syntax looks like:
std::vector<std::unique_ptr<test1>> vec =
v(std::move(u1));
where the list of arguments can be empty.
Live example
Supporting variant allocators is left as an exercise to the user. Add another type to make_vector called A, and have it default to void. If it is void, swap it for std::allocator<T> for whatever type T is chosen for the vector. In the return type deduction version, do something similar.
You're calling the vector constructor ((7) on the linked page) that takes an initializer_list<T> argument. An initializer_list only allows const access to its elements, so the vector must copy the elements, and this, of course, fails to compile.
The following should work
std::unique_ptr<test1> us(new test1());
std::vector<std::unique_ptr<test1>> vec;
vec.push_back(move(us));
// or
vec.push_back(std::unique_ptr<test1>(new test1()));
// or
vec.push_back(std::make_unique<test1>()); // make_unique requires C++14
You could use the vector constructor that takes two iterators, but the solution is still not a one-liner because it requires you to define a temporary array that you can then move from.
std::unique_ptr<test1> arr[] = {std::make_unique<test1>()};
std::vector<std::unique_ptr<test1>> vec{std::make_move_iterator(std::begin(arr)),
std::make_move_iterator(std::end(arr))};
I just dont know how to do it..
Basically, if each template specialization type (T) have different parameters for its initialization, how can a generalized ResourceCache load/create a resource?
template< class T>
class ResourceCache{
T* cache[100];
T* LoadResource(different parameters for different T ){//used in a cache miss..
Create( different parameters for different T );
}
}
If I use abstraction for, i.e., a IResourceParams class, my ResourceCache will not be able to use its own known type resource data without using polymorphism, its kinda stupid, since at runtime he knows what the type is, id be tottaly doing shit at runtime in prol of a compile time facility...I guess..
On my current try I created a templated IResourceDesc that have a virtual T* Create() method, so you need to derive for add data and specialize the Create method, but it sucks, because I cant have a collection of IResourceDesc in the ResourceCache class ( for comparing current loaded ones, acquiring cached resources by desc, etc)...
In C++11, this is rather easy with a variadic template and perfect-forwarding:
#include <utility>
template<class... Args>
T* LoadResource(Args&&... args){
unsigned dest_index = /* pick it */ 0;
cache[dest_index] = new T(std::forward<Args>(args)...);
return cache[dest_index];
}
For C++03, either provide ~10 overloads with different number of parameters or go for the in-place factory style:
template< class T>
class ResourceCache{
T* cache[100];
template<class Factory>
T* LoadResource(Factory const& f){
unsigned dest_index = /* pick cache slot */ 0;
void* dest = operator new(sizeof(T));
cache[dest_index] = f.construct(dest);
return cache[dest_index];
}
}
template<class T, class A1>
struct in_place_factory1{
in_place_factory1(A1 const& a1) : _arg1(a1) {}
int* construct(void* dest) const{
return new (dest) T(_arg1);
}
private:
A1 const& _arg1; // make sure the original argument outlives the factory
};
// in code
ResourceCache<int> cache;
int arg = 5;
int* res = cache.LoadResource(in_place_factory1<int,int>(arg));
In-place factories are basically an inferior version of perfect-forwarding variadic template functions that can emplace the object directly into the containers storage without requiring an already complete object for a copy.
I am trying to write a generic allocator class that does not really release an object's memory when it is free()'d but holds it in a queue and returns a previously allocated object if a new one is requested. Now, what I can't wrap my head around is how to pass arguments to the object's constructor when using my allocator (at least without resorting to variadic templates, that is). The alloc() function i came up with looks like this:
template <typename... T>
inline T *alloc(const &T... args) {
T *p;
if (_free.empty()) {
p = new T(args...);
} else {
p = _free.front();
_free.pop();
// to call the ctor of T, we need to first call its DTor
p->~T();
p = new( p ) T(args...);
}
return p;
}
Still, I need the code to be compatible with today's C++ (and older versions of GCC that do not support variadic templates). Is there any other way to go about passing an arbitrary amount of arguments to the objects constructor?
When you need to target pre-C++0x compilers you need to provide pseudo-variadic templates, i.e. you need to provide a template function for every needed arity:
template<class T>
T* alloc() {
/* ... */
}
template<class T, class A0>
T* alloc(const A0& a0) {
/* ... */
}
/* ... */
You can use preprocessor metaprogramming though to handle the repititions, e.g. by using Boost.Preprocessor or by simply generating the functions using a simple script.
Following is a simple example using Boost.PP:
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
template<class T>
T* alloc() {
return new T;
}
#define FUNCTION_ALLOC(z, N, _) \
template<class T, BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(N), class T)> \
T* alloc(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, BOOST_PP_INC(N), const T, &p)) { \
return new T( \
BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(N), p) \
); \
}
BOOST_PP_REPEAT(10, FUNCTION_ALLOC, ~)
#undef FUNCTION_ALLOC
This generates you alloc() template functions for up to 10 arguments.
The pre-C++11 solution to the problem is to provide only one simple alloc function which constructs a copy of its argument. This is the way C++03 allocators and all the containers worked, for more than 20 years. Applying it to your code it becomes:
template <typename T>
inline T *alloc(const &T arg) {
T *p;
if (_free.empty()) {
p = new T(arg);
} else {
p = _free.front();
_free.pop();
// to call the ctor of T, we need to first call its DTor
p->~T();
p = new( p ) T(arg);
}
return p;
}
And then you call it as:
// copy construct T into the allocator's memory:
instance_of_your_allocator.alloc(T(1, 2, 3));
The downside of this approach is that it requires a copy-constructor to be available, and its potentially a costly operation.
One more example:
vector<T> vec;
vec.push_back(T(1, 2, 3)); // C++03 way, uses move cons-tor in C++11 if possible.
vec.emplace_back(1, 2, 3); // C++11 way, constructs in-place