C++ about generic initialization in templates - c++

I am writing a generic function like below.
template<class Iterator, class T>
void foo(Iterator first, Iterator last) {
T a;
cout << a << endl;
// do something with iterators
}
typedef vector<double>::iterator DblPtr;
vector<double> values;
foo< DblPtr, int>();
This functions prints out an undefined value for variable a, while if I change the initialization into
///
T a = T()
cout << a << endl;
// do something with iterators
I can see that the initialized value is 0 as I am expecting.
If I call T a the variable is initialized with the default value, but if i call T a = T() I believe that due to optimization the copy constructor should be called with the value of T() that is still the default one.
I cannot understand what is the difference behind these 2 lines and the reason why this happens?

First of all, default initiaization of built-in types such as int leaves them uninitialized. Value initialization leaves them zero-initialized. As for your example
This is a default initialization:
T a;
This is a value initialization, using copy initialization:
T a = T();
You are right that copies can be elided here, so this has the effect of creating a single value-initialized T object. However, it does require that T be copyable or move-copyable. This is the case with built-in types, but it is a restriction to bear in mind.
The copy initialization syntax is required because this is a function declaration:
T a();
but C++11 allows you to value-initialize like this:
T a{};

Related

Regarding struct initialization list in C++ [duplicate]

The following code can pass compiling and will print 0 on the console. I saw similar code in STL. Does type int in C++ have a constructor? Is int() a call of some defined function?
int main()
{
int a = int();
cout << a << endl;
return 0;
}
In this context,
int a = int(); // 1)
it value-initializes a, so that it holds value 0. This syntax does not require the presence of a constructor for built-in types such as int.
Note that this form is necessary because the following is parsed as a function declaration, rather than an initialization:
int a(); // 2) function a() returns an int
In C++11 you can achieve value initialization with a more intuitive syntax:
int a{}; // 3)
Edit in this particular case, there is little benefit from using 1) or 3) over
int a = 0;
but consider
template <typename T>
void reset(T& in) { in = T(); }
then
int i = 42;
reset(i); // i = int()
first, we start with this syntax:
type variableName = type();
this syntax is called value initialization of a variableName, or in other word we say a variableName is zero initialized.
But, what is the meaning of the value initialization.
if the type of a variableName is a built-in/scalar type like (int, char, ...),
value initialization mean that a variableName is initialized with the value zero.
and if the type is a complex type like (classes, structs, ...) mean that a variableName is initialized by calling its default constructor.
int() is the constructor of class int. It will initialise your variable a to the default value of an integer, i.e. 0.
Even if you don't call the constructor explicitly, the default constructor, i.e. int() , is implicitly called to initialise the variable.
Otherwise there will be a garbage value in the variable.

Why does std::map::operator[] assignment require an argumentless constructor?

I have the following minimal example reproducing an error in my code:
#include <unordered_map>
#include <iostream>
class B
{
public:
B(int b) : m_b{ b } {}
int m_b;
};
int main()
{
using std::cout, std::endl;
std::unordered_map<int, B> ab{};
ab[1] = B(3);
//ab.insert(std::pair<int, B>(1, B(3)));
cout << ab[1].m_b << endl;
}
This fails with a long and unwieldy error which basically amounts to saying that there is no constructor for B without any arguments. The error stems from ab[1] = B(3) Why is that needed? And why does using insert instead of operator[] not need that constructor?
Bonus points for why this line in my original code:
Vec2 pos{ m_orbits[&p].positionAtTime(m_time + dt) };
also requires a non - parameterized constructor. I could not reproduce that error in my minimal example, but m_orbits is an unordered map with pointers to Particle objects as keys and Orbit objects as values. positionAtTime is a const member function of Orbit that calculates the position of a particle in the orbit at a certain time.
Why is [a constructor for B without any arguments] needed?
This is because std::map::operator[] required the mapped_type (i.e. in your case B) to be default constructable.
Inserts value_type(key, T()) if the key does not exist. This function is equivalent to return insert(std::make_pair(key, T())).first->second;
key_type must meet the requirements of CopyConstructible.
mapped_type must meet the requirements of CopyConstructible and DefaultConstructible.
If an insertion is performed, the mapped value is value-initialized (default-constructed for class types, zero-initialized otherwise) and a reference to it is returned.
When you provide a user defined constructor (i.e. B(int b)), the compiler will not generate a default constructor automatically, and thereby A can not be default construable.
If some user-declared constructors are present, the user may still force the automatic generation of a default constructor by the compiler that would be implicitly-declared otherwise with the keyword default.
Hence, the above error!
why does using insert instead of operator[] not need that constructor?
Because std::map::insert relies on the value_type (i.e. std::pair<const Key, T>). For your ab this is std::pair<const int, B>. From the cppreference.com the function overloads:
1-3) Inserts value. The overload (2) is equivalent to emplace(std::forward<P>(value)) and only participates in overload resolution if std::is_constructible<value_type, P&&>::value == true.
4-6) Inserts value in the position as close as possible, just prior(since C++11), to hint. The overload (5) is equivalent to emplace_hint(hint, std::forward<P>(value)) and only participates in overload resolution if std::is_constructible<value_type, P&&>::value == true.
So as long as B is constructable the std::pair<const int, B> also can be constructed and std::map::insert can be work.

Which type trait would indicate that type is memcpy assignable? (tuple, pair)

I would like to know what type introspection I can do to detect types that assignable by simply raw memory copy?
For example, as far I understand, built-in types tuples of built-in types and tuple of such tuples, would fall in this category.
The motivation is that I want to transport raw bytes if possible.
T t1(...); // not necessarely default constructible
T t2(...);
t1 = t2; // should be equivalent to std::memcpy(&t1, &t2, sizeof(T));
// t1 is now an (independent) copy of the value of t2, for example each can go out of scope independently
What type_trait or combination of type_traits could tell at compile time if assignment can be (in principle) replaced by memcpy?
I tried what would work for the types I would guess should fullfil this condition and to my surprise the only one that fit the behavior is not std::is_trivially_assignable but std::trivially_destructible.
It makes sense to some level, but I am confused why some other options do not work with the expected cases.
I understand that there may not be a bullet proof method because one can always write a class that effectively is memcopyable, that cannot be "detected" as memcopyable, but I am looking for one that works for the simple intuitive cases.
#include<type_traits>
template<class T> using trait =
std::is_trivially_destructible
// std::is_trivial
// std::is_trivially_copy_assignable
// std::is_trivially_copyable // // std::tuple<double, double> is not trivially copyable!!!
// std::is_trivially_default_constructible
// std::is_trivially_default_constructible
// std::is_trivially_constructible
// std::is_pod // std::tuple<double, double> is not pod!!!
// std::is_standard_layout
// std::is_aggregate
// std::has_unique_object_representations
<T>
;
int main(){
static_assert((trait<double>{}), "");
static_assert((trait<std::tuple<double, double>>{}), "");
static_assert((not trait<std::tuple<double, std::vector<double>>>{}), "");
static_assert((not trait<std::vector<double>>{}), "");
}
Of course my conviction that tuple should be memcopyable is not based on the standard but based on common sense and practice. That is, because this is generally ok:
std::tuple<double, std::tuple<char, int> > t1 = {5.1, {'c', 8}};
std::tuple<double, std::tuple<char, int> > t2;
t2 = t1;
std::tuple<double, std::tuple<char, int> > t3;
std::memcpy(&t3, &t1, sizeof(t1));
assert(t3 == t2);
As a proof of principle, I implemented this. I added a couple of conditions related to the size to avoid some possible misleading specialization of std::tuple.
template<class T>
struct is_memcopyable
: std::integral_constant<bool, std::is_trivially_copyable<T>{}>{};
template<class T, class... Ts>
struct is_memcopyable<std::tuple<T, Ts...>> :
std::integral_constant<bool,
is_memcopyable<T>{} and is_memcopyable<std::tuple<Ts...>>{}
>
{};
template<class T1, class T2>
struct is_memcopyable<std::pair<T1, T2>> :
std::integral_constant<bool,
is_memcopyable<T1>{} and is_memcopyable<T2>{}
>
{};
This is a very limited workaround because a class like:
struct A{ std::tuple<double, double> t; };
will still unfortunately be reported as non trivially copyable and non memcopyable.
The correct test is in fact std::is_trivially_copyable, which allows use of memcpy for both making a new object and modifying an existing one.
Although you may be surprised that these return false for types where your intuition tells you that memcpy ought to be ok, they are not lying; the Standard indeed makes memcpy undefined behavior in these cases.
In the particular case of std::pair, we can get some insight into what goes wrong:
int main()
{
typedef std::pair<double,double> P;
std::cout << "\nTC: " << std::is_trivially_copyable<P>::value;
std::cout << "\nTCC: " << std::is_trivially_copy_constructible<P>::value;
std::cout << "\nTCv: " << std::is_trivially_constructible<P, const P&>::value;
std::cout << "\n CC: " << std::is_copy_constructible<P>::value;
std::cout << "\n MC: " << std::is_move_constructible<P>::value;
std::cout << "\nTCA: " << std::is_trivially_copy_assignable<P>::value;
std::cout << "\nTCvA:" << std::is_trivially_assignable<P, const P&>::value;
std::cout << "\n CA: " << std::is_copy_assignable<P>::value;
std::cout << "\n MA: " << std::is_move_assignable<P>::value;
std::cout << "\nTD: " << std::is_trivially_destructible<P>::value;
}
TC: 0
TCC: 1
TCv: 1
CC: 1
MC: 1
TCA: 0
TCvA:0
CA: 1
MA: 1
TD: 1
Evidently it isn't trivially copy assignable.1
The pair assignment operator is user-defined, so not trivial.
1I think that clang, gcc, and msvc are all wrong here, actually, but if it satisfied std::_is_trivially_copy_assignable it wouldn't help, because TriviallyCopyable requires that the copy constructor, if not deleted, is trivial, and not the TriviallyCopyAssignable trait. Yeah, they're different.
A copy/move assignment operator for class X is trivial if it is not user-provided and...
vs
is_assignable_v<T, const T&> is true and the assignment, as defined by
is_assignable, is known to call no operation that is not trivial.
The operations called by pair<double, double>'s copy assignment operator are the assignments of individual doubles, which are trivial.
Unfortunately, the definition of trivially copyable relies on the first, which pair fails.
A trivially copyable class is a class:
where each copy constructor, move constructor, copy assignment operator, and move assignment operator is either deleted or trivial,
that has at least one non-deleted copy constructor, move constructor, copy assignment operator, or move assignment operator, and
that has a trivial, non-deleted destructor.
This is only a partial answer to your question:
Type traits don't necessarily mean what their name says literally.
Specifically, let's take std::is_trivially_copyable. You were - rightly - surprised that a tuple of two double's is not trivially copyable. How could that be?!
Well, the trait definition says:
If T is a TriviallyCopyable type, provides the member constant value equal true. For any other type, value is false.
and the TriviallyCopyable concept has the following requirement in its definition:
Every copy constructor is trivial or deleted
Every move constructor is trivial or deleted
Every copy assignment operator is trivial or deleted
Every move assignment operator is trivial or deleted
At least one copy constructor, move constructor, copy assignment operator, or move assignment operator is non-deleted
Trivial non-deleted destructor
Not quite what you would expect, right?
With all in mind, it's not necessarily the case that any of the standard library traits would combine to fit the exact requirements of "constructible by memcpy()'ing".
To try and answer your question: std::memcpy() does not have any direct requirements but it does have these stipulations:
Copies count bytes from the object pointed to by src to the object pointed to by dest. Both objects are reinterpreted as arrays of unsigned char.
If the objects overlap, the behavior is undefined.
If either dest or src is a null pointer, the behavior is undefined, even if count is zero.
If the objects are not TriviallyCopyable, the behavior of memcpy is not specified and may be undefined.
Now to have the qualifications that an object is Trivially Copyable the following conditions or requirements must be met:
Every copy constructor is trivial or deleted
Every move constructor is trivial or deleted
Every copy assignment operator is trivial or deleted
Every move assignment operator is trivial or deleted
at least one copy constructor, move constructor, copy assignment operator, or move assignment operator is non-deleted
Trivial non-deleted destructor
This implies that the class has no virtual functions or virtual base classes.
Scalar types and arrays of TriviallyCopyable objects are TriviallyCopyable as well, as well as the const-qualified (but not volatile-qualified) versions of such types.
Which leads us to std::is_trivially_copyable
If T is a TriviallyCopyable type, provides the member constant value equal true. For any other type, value is false.
The only trivially copyable types are scalar types, trivially copyable classes, and arrays of such types/classes (possibly const-qualified, but not volatile-qualified).
The behavior is undefined if std::remove_all_extents_t is an incomplete type and not (possibly cv-qualified) void.
with this nice feature since c++17:
Helper variable template
template< class T >
inline constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value;
And you would like to try and use a type_trait to use std::tuple<> with std::memcpy().
But we need to ask ourselves if std::tuple is Trivially Copyable and why?
We can see the answer to that here: Stack-Q/A: std::tuple Trivially Copyable? and according to that answer; it is not because the standard does not require the copy/move assignment operators to be trivial.
So the answer that I would think that is valid would be this: No std::tuple is not Trivially Copyable but std::memcpy() doesn't require it to be but only states that if it isn't; it is UB. So can you use std::tuple with std::memcpy? I think so, but is it safe? That can vary and can produce UB.
So what can we do from here? Take a risk? Maybe. I found something else that is related but have not found anything out about it regarding if it is Trivially Copyable. It is not a type_trait, but it is something that might be able to be used in conjunction with std::tuple & std::memcpy and that is std::tuple_element. You might be able to use this to do the memcpy, but I'm not fully sure about it. I have searched to find out more about std::tuple_element to see if it is Trivially Copyable but haven't found much so all I can do is a test to see what Visual Studio 2017 says:
template<class... Args>
struct type_list {
template<std::size_t N>
using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
};
int main() {
std::cout << std::boolalpha;
std::cout << std::is_trivially_copyable<type_list<int, float, float>>::value << '\n';
std::cout << std::is_trivially_copyable<std::tuple<int, float, float>>::value << '\n';
_getch(); // used to stop visual studio debugger from closing.
return 0;
}
Output:
true
false
So it appears if we wrap std::tuple_element in a struct it is Trivially Copyable. Now the question is how do you integrate this with your std::tuple data sets to use them with std::memcpy() to be type safe. Not sure if we can since std::tuple_element will return the types of the elements within a tuple.
If we even tried to wrap a tuple in a struct as such:
template<class... Args>
struct wrapper {
std::tuple<Args...> t;
};
And we can check it by:
{
std::cout << std::is_trivially_copyable< wrapper<int, float, float> >::value << std::endl;
}
It is still false. However we have seen were std::tuple was already used in the first struct and the struct returned true. This may be of some help to you, to ensure you can safely use std::memcpy, but I can not guarantee it. It is just that the compiler seems to agree with it. So this might be the closest thing to a type_trait that might work.
NOTE: - All the references about memcpy, Trivially Copyable concepts, is_trivially_copyable, std::tuple & std::tuple_element were taken from cppreference and their relevant pages.

Efficient direct initialization of a std::vector

I have a struct, say
struct A {
A(int n) : n(n) {}
int n;
};
and I want to initialize a std::vector with some elements. I can do this by using an initialization list, or by emplacing the new elements:
// 1st version: 3 ctors, 3 copy ctors, 3 dtors
std::vector<A> v1{1, 2, 3};
// 2nd version: 3 ctors
std::vector<A> v2;
v2.reserve(3);
v2.emplace_back(4);
v2.emplace_back(5);
v2.emplace_back(6);
As the comments show, the first version calls 3 constructors, 3 copy constructors, and 3 destructors. The version with emplace only uses 3 constructors.
Question: Obviously the second version is better, but the first version is more succinct. Can I have the best of both worlds? Can I do a direct initialization without the extra cost?
(Here's a longer version of the A struct that shows what's happening.)
Since A is convertible from int, you can use the range constructor of vector:
auto inits = {1, 2, 3};
std::vector<A> v1{std::begin(inits), std::end(inits)};
Or in a single declaration-statement (assuming you can rely on RVO):
auto v1 = [inits={1, 2, 3}] { return std::vector<A>{std::begin(inits), std::end(inits)}; }();
Expanding on #ecatmur's answer, I've developed a piece of code that allows a very general solution for any type of vector and for any constructor calls. The constructor parameters for each element of the vector are stored in a tuple (of & or && as appropriate) which are then perfect-forwarded when the element is built. Each element is constructed only once, essentially equivalent to emplace_back. This forwarding would even allow a vector of move-only types to be built such as unique_ptr<?>.
(Update, due to RVO it should simply construct them in place. Unfortunately, however, the element type does require at least a copy-constructor or move-constructor to be visible, even if they are actually skipped by the optimizer. This means you can build a vector of unique_ptr, but not of mutex.)
auto v2 = make_vector_efficiently<A>(
pack_for_later(1) // 1-arg constructor of A
,pack_for_later(2,"two") // 2-arg constructor of A
,pack_for_later(3) // 1-arg constructor of A
);
The above code will create a vector<A> with three elements. In my example, A has two constructors, one which takes int,string as parameters.
pack_for_later builds a tuple that stores its parameters as &/&& references. That is then converted into on object (of type UniquePointerThatConverts, that has the desired conversion operator, in this case operator A().
Within make_vector_efficiently, an initializer list of these converter objects is built and then vector is constructed with the begin() and
end() of the initializer_list. You might expect that these iterators would be required to have type T* in order to construct a vector<T>, but it is sufficient that the type the iterator points to can convert to T.
The constructor then uses placement new to (copy-)construct from the converted object. But, thanks for RVO, the copy won't happen and the converter will be effectively doing the equivalent of emplace_back for us.
Anyway, any feedback appreciated. Finally, it's trivial to extend this to other containers besides vector.
Full code on Coliru Should work on any C++11 compiler.
Some more detailed notes, and copies of the important functions:
pack_for_later simply builds a std::tuple. The standard make_tuple isn't good enough as it ignores references. Each element of the tuple built by pack_for_later is a reference (& or && as appropriate, depending on whether the original parameter was an lvalue or rvalue)
template<typename ...T>
std:: tuple<T&&...> pack_for_later(T&&... args) {
// this function is really just a more
// 'honest' make_tuple - i.e. without any decay
return std:: tuple<T&&...> (std::forward<T>(args)...);
}
Next, make_vector_efficiently is the function that brings is all together. It's first parameter is the 'Target' type, the type of the elements in the vector we wish to create. The collection of tuples is converted into our special converter type UniquePointerThatConverts<Target> and the vector is constructed as discussed above.
template<typename Target, typename ...PackOfTuples>
auto make_vector_efficiently(PackOfTuples&&... args)
-> std::vector<Target>
{
auto inits = { UniquePointerThatConverts<Target>(std::forward<PackOfTuples>(args))...};
return std::vector<Target> {std::begin(inits), std::end(inits)};
}
Because A can have multiple constructors, and we want to be able to use any and all of them, pack_for_later can return many different types (don't forget about lvalues and rvalues too). But we need a single type to build the init list from. Therefore, we define a suitable interface:
template<typename Target>
struct ConvInterface {
virtual Target convert_to_target_type() const = 0;
virtual ~ConvInterface() {}
};
Each tuple is therefore converted to an object that implements this interface by make_Conv_from_tuple. It actually returns a unique_ptr to such an object which is then stored in a UniquePointerThatConverts that has the actual conversion operator. It is this type that is stored in the init list which is used to initialize the vector.
template<typename Target>
struct UniquePointerThatConverts {
std:: unique_ptr<ConvInterface<Target>> p; // A pointer to an object
// that implements the desired interface, i.e.
// something that can convert to the desired
// type (Target).
template<typename Tuple>
UniquePointerThatConverts(Tuple&& p_)
: p ( make_Conv_from_tuple<Target>(std:: move(p_)) )
{
//cout << __PRETTY_FUNCTION__ << endl;
}
operator Target () const {
return p->convert_to_target_type();
}
};
And, of course, the actual conversion operator which constructs from the pack.
template<typename Target, typename ...T>
struct Conv : public ConvInterface<Target> {
std::tuple<T...> the_pack_of_constructor_args;
Conv(std::tuple<T...> &&t) : the_pack_of_constructor_args(std:: move(t)) {}
Target convert_to_target_type () const override {
using idx = typename make_my_index_sequence<sizeof...(T)> :: type;
return foo(idx{});
}
template<size_t ...i>
Target foo(my_index_sequence<i...>) const {
// This next line is the main line, constructs
// something of the Target type (see the return
// type here) by expanding the tuple.
return {
std:: forward
< typename std:: tuple_element < i , std::tuple<T...> > :: type >
(std:: get<i>(the_pack_of_constructor_args))
...
};
}
};

Is it safe to pass as argument a member of an object which is moving

#include <iostream>
#include <string>
#include <map>
struct A {
int n { 42 };
std::string s { "ciao" };
};
int main() {
A a;
std::map<std::string, A> m;
std::cout << "a.s: " << a.s << std::endl; // print: "a.s: ciao"
m.emplace(a.s, std::move(a)); // a.s is a member of a, moved in the same line
std::cout << "in map: " << m.count("ciao") << std::endl; // print: "in map: 1"
std::cout << "a.s: " << a.s << std::endl; // print: "a.s: " (as expected, it has been moved)
}
Is it safe to pass as an argument a member of a "moving" object? In this case, emplace seems to work: the map has the expected key.
Interesting. I think it's safe, for convoluted reasons. (For the record, I also consider it very bad style -- an explicit copy costs you nothing here, since it will be moved into the map.)
First of all, the actual function call is not a problem. std::move only casts a to an rvalue reference, and rvalue references are just references; a is not immediately moved. emplace_back forwards its parameters to a constructor of std::pair<std::string, A>, and this is where things get interesting.
So, which constructor of std::pair is used? It has rather many, but two are relevant:
pair(const T1& x, const T2& y);
template<class U, class V> pair(U&& x, U&&y);
(See 20.3.2 in the standard), where T1 and T2 are the template arguments of std::pair. As per 13.3, we end up in the latter with U == const T1& and V == T2, which makes intuitive sense (otherwise moving into a std::pair would be effectively impossible). This leaves us with a constructor of the form
pair(const T1& x, T2 &&y) : first(std::forward(x)), second(std::forward(y)) { }
as per 20.3.2 (6-8).
So, is this safe? Helpfully, std::pair is defined in some detail, including memory layout. In particular, it states that
T1 first;
T2 second;
come in this order, so first will be initialized before second. This means that in your particular case, the string will be copied before it is moved away, and you're safe.
However, if you were doing it the other way around:
m.emplace(std::move(A.s), A); // huh?
...then you'd get funny effects.
What happens when you call m.emplace(a.s, std::move(a)); is that you are passing an l-value reference to a.s and an r-value reference to a to the emplace function. Whether this is safe depends on the implementation of that function. If it first rips the guts out of the second argument and then tries to use the first argument, you'll likely have a problem. If it first uses the first argument and then rips the guts out of the second argument, no problem. Since this is a standard library function, you cannot rely on the implementation, so we cannot conclude that the code is safe.
To make it safe, you can make sure that a copy of the string is made before the contents of the string are moved out of a.
m.emplace(std::string(a.s), std::move(a));
Now you are passing an r-value reference to a temporary copy of a.s and an r-value reference to a to the emplace function. So, it's safe in this case, because std::map::emplace takes a set of universal references. If you would do the same with a function that takes it second argument by value, it's unsafe, because the move constructor could be called before the copy of a.s is made (since evaluation order of function arguments is unspecified). Knowing that, this code is probably too smart to be maintained.
So, the clearest code is something like:
auto key = a.s;
m.emplace(std::move(key), std::move(a));