I need to have elements in a std::vector aligned to some given step in memory. For example, in the program as follows:
#include <vector>
#include <iostream>
struct __attribute__((aligned(256))) A
{
};
int main()
{
std::vector<A> as(10);
std::cout << &as[0] << std::endl;
std::cout << &as[1] << std::endl;
}
I would expect that the last two digits in printed numbers will be ‘00’.
In practice, I see that it is true in Visual Studio 2019, and in gcc 8+. But can I be absolutely sure, or is it just a coincidence and some custom allocator in std::vector (like boost::alignment::aligned_allocator) is necessary?
In practice, I see that it is true in Visual Studio 2019, and in gcc 8+. But can I be absolutely sure, or is it just a coincidence and some custom allocator in std::vector (like boost::alignment::aligned_allocator) is necessary?
There is no reason to expect that, provided the absence of bugs in the implementation of the respective compiler (which can however be checked on the assembly level, if required).
Since C++11, there is the alignas-specifier which allows you to enforce the alignment in a standardized way. Consequently, the standard allocator will call operator new upon calling allocator::allocate(), to which it will forward the alignment information according to the documentation. Thus, the standard allocator already respects alignment needs, if specified. However, of course if the global operator new is overloaded by a custom implementation, no such guarantee can be made.
Related
Should this code print empty (Clang & GCC), or not empty (Visual C++)?
Should that change if I remove reserve()? What about using emplace() instead of insert()?
#include <stdio.h>
#include <memory>
#include <vector>
int main()
{
std::vector<std::shared_ptr<int> > v;
v.reserve(10); // Should this affect the output?
v.push_back(std::make_shared<int>(0));
v.insert(v.begin(), std::move(v.front())); // Does 'emplace' vs. 'insert' matter?
printf("Element 0 is: %s\n", v[0] ? "not empty" : "empty");
return 0;
}
Logically not empty makes more sense to me for insert, because the caller of insert is requesting movement from a particular object, and we need to ensure that's what we're moving from. Moreover, it seems silly for reserve() to affect which element ends up where.
However, that would imply both libstdc++ (GCC) and libc++ (Clang) are buggy, which doesn't seem likely.
Perhaps more interestingly, I'm less certain about emplace. I'm inclined to think using emplace should logically output empty, because the caller is requesting construction to occur at in the object's correct place ("emplace"), which requires movement to occur before construction.
What is the correct behavior of moving from a container into itself? Does it depend on the specifics of which of insert/emplace/reserve are called? Is it implementation-defined?
For what it's worth, cppreference.com says the following for emplace:
If the required location has been occupied by an existing element, the inserted element is constructed at another location at first, and then move assigned into the required location.
but that goes against what both GCC and Clang do for emplace, as well as against my expectation above (which differs from my expectation for insert).
According to https://en.cppreference.com/, std::vector<bool> has a class template specialization, while std::array<bool, N> does not. Which are the reasons why it is not provided?
When std::vector was introduced, a specialization for bool was considered a good idea. Basically, at that time, the average computer had 4 MB of memory, so saving computer memory was quite important. Nowadays we just say "memory is cheap" (quote from Uncle Bob).
Later it turned out that this specialization creates more problems than it is worth.
The issue is that the address to one of the elements of such a vector is a complex object (it has to store information on which bit holds which value) compared to regular old-fashioned C-array bool a[].
Since compatibility must be retained, this specialization can't be dropped, but based on that lesson, the same approach was not applied to std::array.
Another reason is that std::array is supposed to be a C-array wrapper, so it must be as similar to bool a[N] as possible, and must produce the same machine code when used.
And the last thing, as Cody Gray points out in a comment under question, std::bitset is a constant size array of bits, so such functionality is already available (and can be used if needed).
This is a question about history of evolution of C++. In hindsight a possible explanation is:
std::vector<bool> was a mistake. It is a major annoyance that a std::vector<bool> is very different from std::vector<T>. Generic code that works with vectors often needs a special case for std::vector<bool>. And users often have to apply weird workarounds like using a std::vector<char> in place of std::vector<bool>. Now we cannot go back without breaking lots of existing code. With what we know now, maybe std::vector<bool> would never have made it into C++.
std::array was added only in C++11. There was no reason to make the same mistake again.
The initial motivation to specialize std::vector for bool was to optimize memory usage.
However this was a bad idea as this specialization behaves differently than usual std::vector (see example below).
This error was not reproduced later with C++11's std::array
#include <array>
#include <vector>
int main()
{
std::vector<int> i_v(4);
int i_a = *&i_v[3]; // ok
std::vector<bool> v(4);
bool a = *&v[3]; // Compile-time error
std::array<bool,4> w;
bool b = *&w[3]; // ok
}
The std::vector<bool> specialization was introduced as early as 1994, as per lib.vector.bool of WG21/N0545(1) [emphasis mine]:
23.1.6 Class vector<bool> [lib.vector.bool]
To optimize space allocation, a specialization for bool is provided: [...]
with a motivation to optimize for space allocation, a resource that was sparse back then.
In retrospect, this turned out to be quite a bad idea, and the original motivation was made moot with the rapid growth of available space in computer hardware.
std::array, on the other hand, was introduced much later, in C++11, alongside e.g. auto type deduction, a mechanism which highlighted yet another problem with the std::vector<bool> specialization. Naturally the library spec writers did not repeat the same mistake of std::vector<bool> when designing std::array.
E.g., the following snippet
#include <type_traits>
#include <vector>
int main() {
std::vector<bool> v{false, false, true, true};
auto bool_value = v[1];
static_assert(std::is_same_v<decltype(bool_value), bool>, ""); // Error!
}
fails with the error message that bool_value is not of type bool, but of the cryptic type (implementation-defined)
error: static_assert failed due to requirement
'std::is_same_v<
std::__1::__bit_reference<
std::__1::vector<bool, std::__1::allocator<bool>>, true>,
bool>' ""
(1) Working Paper for Draft Proposed International Standard for Information Systems-- Programming Language C++.
Can I safely assume that an address of the first element of a std::pair can be used as an address of two element array? Of course both elements of the pair are of the same type. Following code works in g++ 7.2, clang 3.8 and vc++14
void foo(int* a)
{
std::cout << std::to_string(a[0]) << ", " << std::to_string(a[1]) << std::endl;
}
int main()
{
std::pair<int, int> bar(42, 24);
foo(&bar.first);
return 0;
}
As std::pair is rather simple class I am convinced that this case can be generalized, but I'm not sure to what extent. For example, does it being a template class have any impact on the question?
If I cannot safely do that, why? If it's considered a valid code, what guarantees this?
Making my comment into an answer:
It is categorically not allowed to read beyond object boundaries, except for arrays (as MSalters pointed out). While a single variable can be considered an array of length 1 (so that a[0] is allowed by virtue of its definition as *(a+0)), reading its non-existing "second element" via a[1] is undefined behavior because it reads beyond bar.first's boundaries. That both objects are probably part of a larger aggregate object (whose implementation is unknown) does not change that.
Note that many boundary transgressions like this one work, with known architectures, compilers, libraries, and compiler options; this particular one should work everywhere because int is designed to have the natural word size on a given machine and can thus be aligned without padding in a struct, which a std::pair certainly will be; but there is no guarantee, including malicious compilers. In fact, the program as it is presented (namely as one translation unit) can statically be proven ill-formed. A compiler could detect that and reject compilation.
The cpp reference is not saying anything how the the templated struct std::pair has to be defined (http://en.cppreference.com/w/cpp/utility/pair).
It is not guaranteed, that the first and second parameter will be packed together. Even though most implementations will probably look like
template<class A, class B>
struct pair {
[...]
A first;
B second;
[...]
}
For int your code might work. For other types it is a very unsafe to assume how the internals of std::pair looks like.
If you need an array of integers of the elements, you have to copy them into a separate location.
I compiled and ran the following C++ code, blindly trying to create a flexible array member like you can in C:
#include <iostream>
template <typename T>
struct Vector {
int length;
T ts[];
};
Vector<int> ts = {
3,
{10, 10, 10},
};
int main() {
std::cout << sizeof(ts) << std::endl;
std::cout << ts.data[1] << std::endl;
return 0;
}
The code compiles and runs just fine, and gives the same output that C would in the same circumstance (it outputs 4 and then 10).
Now, according to this answer from 2010 what I have written should not be valid C++. Furthermore, according to this wikipedia article, "C++ does not have flexible array members".
My question is, which C++ feature am I actually using in the above code, specifically on the line that says "T ts[];"? Does that code actually do what I think it does in general, or is it undefined behavior?
It is one of those things which are different between C and C++. A flexible array member is valid in C but not C++.
That said, many modern compilers compile C as a subset of C++, taking care to care only when you torque up the compiler error diagnostics.
David Tribble spends a moment on it at his Incompatibilities Between ISO C and ISO C++ page, where he specifically addresses this issue:
C++ does not support flexible array members.
(This feature might be provided as an extension by some C++ compilers, but would probably be valid only for POD structure types.)
So yes, this is undefined behavior. The correct way (in both C and C++) to write such a thing is to give it a non-zero dimension:
template <typename T>
struct Vector {
int length;
T ts[1];
};
You have another issue: you must allocate memory for said object. Simply specifying an initializer is not enough. As far as every access to such a thing exists, the compiler only ever thinks it is its minimal size.
This “range hack” is so called because the programmer explicitly uses/abuses C's (and C++'s) ability to violate range bounds to do something tricky.
The consequences of this are many, including inability to store these things in any standard container, or pass them around by value, or do most anything that eschews handling it through a pointer. It has its place, but for the vast majority of use cases C++ has superior options.
This question already has answers here:
Can std::vector emplace_back copy construct from an element of the vector itself?
(3 answers)
Closed 8 years ago.
I have heard that one of the recommendations of Modern C++ is to use emplace_back instead of push_back for append in containers (emplace_back accept any version of parameters of any constructor of the type storage in the container).
According to the standard draft N3797 23.3.6.5 (1), say that:
Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid. If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of T or by any InputIterator operation there are no effects. If an exception is thrown by the move constructor of a non-CopyInsertable T, the effects are unspecified.
This specify what happen when no reallocation is needed, but leave open the problem when the container need to grow.
In this piece of Code:
#include <iostream>
#include <vector>
int main() {
std::vector<unsigned char> buff {1, 2, 3, 4};
buff.emplace_back(buff[0]);
buff.push_back(buff[1]);
for (const auto& c : buff) {
std::cout << std::hex << static_cast<long>(c) << ", ";
}
std::cout << std::endl;
return 0;
}
Compiled with VC++ (Visual Studio 2013 Update 4) and GCC 4.9.1 (MinGW) in Debug in Windows 8.1.
When compiled with VC++ the output is:
1, 2, 3, 4, dd, 2
When compiled with GCC the output is:
1, 2, 3, 4, 1, 2
Checking the implementation of emplace_back in VC++ the difference is that the first lines of code, check if the container need to grow (and grow if it's needed), in the case that the container need to grow, the reference to the first element (buff[0]) received in the emplace_back method is invalidated and when the actual setting of the value in the new created element of the container happen the value is invalid.
In the case of the push_back work because the creation of the element to append is made in the parameter binding (before the possible grow of the container).
My question is:
This behavior, when the container need to grow because a call to emplace_back and the parameter is a reference to the same container is implementation defined, unspecified or there is a problem in the implementation of one of the compiler (suppose in VC++ as GCC behavior is more close to the expected)?
When you used &operator[], that returned a reference. You then used emplace_back which caused reallocation, and thus invalidated all past references. Both of these rules are well defined. The correct thing that should happen is an exception. I actually expect the VC++ version to throw an exception if you are running the debug version under the debugger.
push_back has the same two rules, which means it will also do the same. I am almost certain, swapping the two lines emplace_back/push_back will result in the same behavior.