I know a pointer to an array and its size. What container can be created from it? I tried to do this:
std::initializer_list<int> foo(arr, arr + size);
It works for the MSVC, but not for the gcc
std::initializer_list is a reference-type designed just for supporting list-initialization, and only has the default-ctor, and implicitly copy-ctor. Any other ctor is an extension.
What you can do is initializing the target-container directly from an iterator-range, without involving any intermediate views.
The standard container to use unless you know better would be std::vector. Or would using a simple view like std::span be enough for you?
If you need an actual data owning container, then what you want is a std::vector. This is going to cost you a copy and an allocation. If all you need is to act like a container, then what you want is the upcoming std::span from C++20. It takes a pointer and a size and wraps it in an interface that is like an array.
MSVS's use of
std::initializer_list<int> foo(arr, arr + size);
is not standard. Per the standard the only constructor for std::initiliazer_list is
constexpr initializer_list() noexcept;
There are kind of two questions here, each with their own answer.
How to convert C array to std::initializer_list?
You can't. It doesn't really make sense to. std::initializer_list is really only used to initialize (as its name implies) objects. It's basically is what is created from the {} notation like this:
myObject obj = {0,1,2,3,4};
Attempting to create an instance of an std::initializer_list isn't really useful in any other sense that I can think of, especially since C++14 it's impossible to create at runtime anyway, since it has a constexpr constructor.
If you have some object foo that accepts an std::initializer_list, like this:
class foo {
foo(std::initializer_list list) {
//...
}
};
And you are wondering how to create this object without anstd::initializer_list, then the answer is to simply add another constructor:
class foo {
// an actual array
foo(type arr[size]) {
//...
}
// as a pointer
foo(type arr*, size_t size) {
//...
}
};
If you are using a third party library, or some other library you don't control, that does not have another constructor, then chances are it's not intended to be used this way. In that case, I would consult your documentation or vendor.
What container can be created from it?
Any sequence container. Most of them have some sort of constructor that accepts pointers to an object (actually, it technically takes iterators, but pointers will work the same in this context) or an array. They are pretty much designed for easy conversion from C arrays. Which one you use will depend on your situation.
Also, std::span (which is not listed as a "sequence container") has been mentioned as a possible container that can get created from a C array at low cost. Although, I can't vouch for them personally, as I'm not too familiar with the upcoming standard.
Final note: If MSVC allows this, then either a) you're possibly in C++11 (though I can't confirm if this was allowed in C++11 either, just that the constructor is not constexpr in C++) or b) it is a compiler bug in MSVC.
Related
I am trying to create a static container which has stack based memory and can hold N instances of T. Much alike std::vector I want currently unused memory to not contain initialized items of T. This is usually solved with placement new but that's not possible to use in constexpr.
Using unions
I found a trick that you can use a union for this as follows:
template <typename value_type>
union container_storage_type
{
struct empty{};
constexpr container_storage_type(): uninitialized{}{}
constexpr container_storage_type(value_type v): value(v){}
constexpr void set(value_type v)
{
*this = literal_container_storage_type{v};
}
empty uninitialized;
value_type value;
};
This lets you store items uninitialized by setting the empty member and this works around the limitation that all members in constexpr have to be initialized.
Now the problem with this approach is that if value_typeis a type that implements operator=, the rule for unions says:
If a union contains a non-static data member with a non-trivial special member function (copy/move constructor, copy/move assignment, or destructor), that function is deleted by default in the union and needs to be defined explicitly by the programmer.
This means that to be able to use this trick, I need to implement operator= in the union too, but how would that look?
constexpr container_storage_type& operator=(const container_storage_type& other)
{
value = other.value; //ATTEMPT #1
//*this = container_storage_type(other.value);ATTEMPT #2
return *this;
}
Attempt #1: This does not seem possible as the compiler complains that changing the active member of a union is simply disallowed in constant expressions.
Attempt #2: This works in the set() method from the previous snippet, as it doesn't change the active member per se, but reassigns the whole union. This trick seems unable to be used in the assignment operator however since that causes endless recursion...
Am I missing something here, or is this truly a dead end for using unions as a placement-new alternative in constexpr?
Are there other alternatives to placement new that I have completely missed?
https://godbolt.org/z/km0nTY Code that illustrates the problem
In C++17, you can't.
The current restrictions on what you cannot do in constant expressions include:
an assignment expression ([expr.ass]) or invocation of an assignment operator ([class.copy.assign]) that would change the active member of a union;
a new-expression;
There really is no way around that.
In C++20, you will be able to, but probably not the way you think. The latter restriction is going to be relaxed in C++20 as a result of P0784 to something like:
a new-expression (8.3.4), unless the selected allocation function is a replaceable global allocation function (21.6.2.1, 21.6.2.2);
That is, new T will become fine but new (ptr) T will still not be allowed. As part of making std::vector constexpr-friendly, we need to be able to manage "raw" memory - but we still can't actually manage truly raw memory. Everything still has to be typed. Dealing with raw bytes is not going to work.
But std::allocator doesn't entirely deal in raw bytes. allocate(n) gives you a T* and construct takes a T* as a location and a bunch of arguments and creates a new object at that location. You may be wondering at this point how this is any different from placement new - and the only difference is that sticking with std::allocator, we stay in the land of T* - but placement new uses void*. That distinction turns out to be critical.
Unfortunately, this has the interesting consequence of your constexpr version "allocates" memory (but it allocates compiler memory, which will get elevated to static storage as necessary - so this does what you want) - but your pure runtime version surely does not want to allocate memory, indeed the whole point would be that it does not. To that end, you will have to use is_constant_evaluated() to switch between the allocating at constant evaluation time and non-allocating at runtime. This is admittedly not beautiful, but it should work.
Your storage can look something like this:
// For trivial objects
using data_t = const array<remove_const_t<T>, Capacity>>;
alignas(alignof(T)) data_t data_{};
// For non-trivial objects
alignas(alignof(T)) aligned_storage_t<T> data_[Capacity]{};
This will allow you to create a const array of non-const objects. Then constructing objects will look something like this:
// Not real code, for trivial objects
data_[idx] = T(forward<Args>(args)...);
// For non-trivial objects
new (end()) T(forward<Args>(args)...);
Placement new is mandatory here. You will be able to have the storage at compile-time, but you cannot construct it at compile-time for non-trivial objects.
You will also need to take into account whether or not your container is zero-sized, etc. I suggest you look at existing implementations for fixed sized vectors and there are even some proposals for constexpr fixed sized vectors like p0843r1.
I would define "trivially movable" by
Calling the move constructor (or the move assignment operator) is
equivalent to memcpy the bytes to the new destination and not calling
the destructor on the moved-from object.
For instance, if you know that this property holds, you can use realloc to resize a std::vector or a memory pool.
Types failing this would typically have pointers to their contents that needs to be updated by the move constructor/assignment operator.
There is no such type traits in the standard that I can find.
I am wondering whether this already has a (better) name, whether it's been discussed and whether there are some libraries making use of such a trait.
Edit 1:
From the first few comments, std::is_trivially_move_constructible and std::is_trivially_move_assignable are not equivalent to what I am looking for.
I believe they would give true for types containing pointers to themselves, since reading your own member seems to fall under "trivial" operation.
Edit 2:
When properly implemented, types which point to themselves won't be trivially_move_constructible or move_assignable because the move ctor / move assignment operator are not trivial anymore.
Though, we ought to be able to say that unique_ptr can be safely copied to a new location provided we don't call its destructor.
I think what you need is std::is_trivially_relocatable from proposal P1144. Unfortunately the proposal didn't make it into C++20, so we shouldn't expect it before 2023. Which is sad, because this type trait would enable great optimizations for std::vector and similar types.
Well, this got me thinking... It is very important to overload type traits of structs that hold a pointer to themselves.
The following code demonstrates how fast a bug can creep in code, when type_traits are not defined properly.
#include <memory>
#include <type_traits>
struct A
{
int a;
int b;
int* p{&a};
};
int main()
{
auto p = std::make_unique<A>();
A a = std::move(*p.get()); // gets moved here, a.p is dangling.
return std::is_move_assignable<A>::value; // <-- yet, this returns true.
}
The expression new T[n] may or may not initialize each object in the array, depending on what T is.
How do I replicate this initialization behavior using an allocator?
struct Foo
{
int x;
Foo() : x(1)
{ }
};
Foo *p = new Foo[1];
assert(p[0].x == 1);
In C++03, the allocator interface only knows one way to initialize objects, and that's to copy from another object. C++11 has more.
You're asking for default initialization, which means (approximately), "either do nothing or call the default constructor". The allocator interface cannot do the latter in C++03.
I suppose you could write something like:
T *ra = allocator.allocate(1);
if (!is_pod<T>::value) {
// in C++03
allocator.construct(ra, T());
// in C++11
allocator.construct(ra);
}
That is_pod test might be wrong, though. Check the standard for exactly what conditions default initialization does nothing. Obviously is_pod doesn't exist in C++03, but I vaguely recall that Boost has something of the kind that works on most implementations.
I think that you're fighting the design here. The allocator interface was designed for use by containers. Containers were designed not to contain uninitialized elements, so they have no use for default initialization.
I'm not a very experienced c++ coder and this has me stumped. I am passing a object (created elsewhere) to a function, I want to be able to store that object in some array and then run through the array to call a function on that object. Here is some pseudo code:
void AddObject(T& object) {
object.action(); // this works
T* objectList = NULL;
// T gets allocated (not shown here) ...
T[0] = object;
T[0].action(); // this doesn't work
}
I know the object is passing correctly, because the first call to object.action() does what it should. But when I store object in the array, then try to invoke action() it causes a big crash.
Likely my problem is that I simply tinkered with the .'s and *'s until it compiled, T[0].action() compliles but crashes at runtime.
The simplest answer to your question is that you must declare your container correctly and you must define an appropriate assigment operator for your class. Working as closely as possible from your example:
typedef class MyActionableClass T;
T* getGlobalPointer();
void AddInstance(T const& objInstance)
{
T* arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **objects**
//whose first element we don't mind losing
//**copy** the instance we've received
arrayFromElsewhere[0] = objInstance;
//now invoke the action() method on our **copy**
arrayFromElsewhere[0].action();
}
Note the signature change to const reference which emphasizes that we are going to copy the original object and not change it in any way.
Also note carefully that arrayFromElsewhere[0].action() is NOT the same as objInstance.action() because you have made a copy — action() is being invoked in a different context, no matter how similar.
While it is obvious you have condensed, the condensation makes the reason for doing this much less obvious — specifying, for instance, that you want to maintain an array of callback objects would make a better case for “needing” this capability. It is also a poor choice to use “T” like you did because this tends to imply template usage to most experienced C++ programmers.
The thing that is most likely causing your “unexplained” crash is that assignment operator; if you don't define one the compiler will automatically generate one that works as a bitwise copy — almost certainly not what you want if your class is anything other than a collection of simple data types (POD).
For this to work properly on a class of any complexity you will likely need to define a deep copy or use reference counting; in C++ it is almost always a poor choice to let the compiler create any of ctor, dtor, or assignment for you.
And, of course, it would be a good idea to use standard containers rather than the simple array mechanism you implied by your example. In that case you should probably also define a default ctor, a virtual dtor, and a copy ctor because of the assumptions made by containers and algorithms.
If, in fact, you do not want to create a copy of your object but want, instead, to invoke action() on the original object but from within an array, then you will need an array of pointers instead. Again working closely to your original example:
typedef class MyActionableClass T;
T** getGlobalPointer();
void AddInstance(T& objInstance)
{
T** arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **pointers**
//whose first element we don't mind losing
//**reference** the instance we've received by saving its address
arrayFromElsewhere[0] = &objInstance;
//now invoke the action() method on **the original instance**
arrayFromElsewhere[0]->action();
}
Note closely that arrayFromElsewhere is now an array of pointers to objects instead of an array of actual objects.
Note that I dropped the const modifier in this case because I don’t know if action() is a const method — with a name like that I am assuming not…
Note carefully the ampersand (address-of) operator being used in the assignment.
Note also the new syntax for invoking the action() method by using the pointer-to operator.
Finally be advised that using standard containers of pointers is fraught with memory-leak peril, but typically not nearly as dangerous as using naked arrays :-/
I'm surprised it compiles. You declare an array, objectList of 8 pointers to T. Then you assign T[0] = object;. That's not what you want, what you want is one of
T objectList[8];
objectList[0] = object;
objectList[0].action();
or
T *objectList[8];
objectList[0] = &object;
objectList[0]->action();
Now I'm waiting for a C++ expert to explain why your code compiled, I'm really curious.
You can put the object either into a dynamic or a static array:
#include <vector> // dynamic
#include <array> // static
void AddObject(T const & t)
{
std::array<T, 12> arr;
std::vector<T> v;
arr[0] = t;
v.push_back(t);
arr[0].action();
v[0].action();
}
This doesn't really make a lot of sense, though; you would usually have defined your array somewhere else, outside the function.
I'm looking for a C++ container that's a cross between boost::array, boost::scoped_array and std::vector.
I want an array that's dynamically allocated via new[] (no custom allocators), contained in a type that has a meaningful copy-constructor.
boost::array is fixed-size, and although I don't need to resize anything, I don't know the size of the array at compile time.
boost::scoped_array doesn't have a copy constructor, and that means that I need to manually add one to each and every class using std::copy (my previous copy-paste intensive solution). This is also error prone, since you better make sure when you add a field that you added the correct initializer to the custom copy constructor; i.e. loads of boilerplate.
std::vector uses some pre-allocation system, and thus does not use operator new[]. This is problematic since it requires custom allocators, and worse, even that's not quite enough since there are some odd corner cases (which I don't fully understand) where return-by-value semantics are concerned that cause problems; I don't want the container to do anything fancy but simply contain a new[]'d array and copy it in it's copy constructor - and preferably overload all the usual suspects to be usable as a collection.
I don't need to resize anything, but the size must be controllable at runtime. Basically, a variant of scoped_array that happens to have a sane copy-constructor (for instance via std::copy) would be fine. Is there a standard collection for something like this?
Basically, I'm looking for a bog-standard dynamically allocated array with value semantics.
Inherit privately from std::vector, and then adjust appropriately. For example remove resize(), and perhaps add setsize() and a bool flag to determine if the size has been set.
Your copy constructor can invoke the std::vector copy constructor, and set the flag automatically to prevent further changes.
Doesn't sound hard to write. Something along the lines of this?
template <typename T> my_array {
T* m_ptr;
size_t m_size;
public:
my_array(size_t sz)
: m_ptr(new T[sz])
, m_size(sz)
{}
my_array(const my_array &other)
: m_ptr(new T[other.m_size])
, m_size(other.m_size)
{
std::copy(other.m_ptr, other.m_ptr + other.m_size, m_ptr);
}
~my_array() {
delete[] m_ptr;
}
// ... operator[], etc.
};
Usual disclaimers - this is off the top of my head, has not been compiled or anything.