Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The future of C++ alignment: passing by value?

Reading the Eigen library documentation, I noticed that some objects cannot be passed by value. Are there any developments in C++11 or planned developments that will make it safe to pass such objects by value?

Also, why is there no problem with returning such objects by value?

like image 550
Neil G Avatar asked Apr 04 '12 21:04

Neil G


People also ask

What is data alignment C?

Data alignment: Data alignment means putting the data in memory at an address equal to some multiple of the word size. This increases the performance of the system due to the way the CPU handles memory.

Why is data alignment needed?

Alignment helps the CPU fetch data from memory in an efficient manner: less cache miss/flush, less bus transactions etc. Some memory types (e.g. RDRAM, DRAM etc.) need to be accessed in a structured manner (aligned "words" and in "burst transactions" i.e. many words at one time) in order to yield efficient results.

Does malloc return aligned memory?

Regular malloc aligns memory suitable for any object type (which, in practice, means that it is aligned to alignof(max_align_t)). This function is useful for over-aligned allocations, such as to SSE, cache line, or VM page boundary.

What is a byte boundary?

Certain SIMD instructions, which perform the same instruction on multiple data, require that the memory address of this data is aligned to a certain byte boundary. This effectively means that the address of the memory your data resides in needs to be divisible by the number of bytes required by the instruction.


2 Answers

It is entirely possible that Eigen is just a terribly written library (or just poorly-thought out); just because something is online doesn't make it true. For example:

Passing objects by value is almost always a very bad idea in C++, as this means useless copies, and one should pass them by reference instead.

This is not good advice in general, depending on the object. It is sometimes necessary pre-C++11 (because you might want an object to be uncopyable), but in C++11, it is never necessary. You might still do it, but it is never necessary to always pass a value by reference. You can just move it by value if it contains allocated memory or something. Obviously, if it's a "look-but-don't-touch" sort of thing, const& is fine.

Simple struct objects, presumably like Eigen's Vector2d are probably cheap enough to copy (especially in x86-64, where pointers are 64-bits) that the copy won't mean much in terms of performance. At the same time, it is overhead (theoretically), so if you're in performance critical code, it may help.

Then again, it may not.

The particular crash issue that Eigen seems to be talking about has to do with alignment of objects. However, most C++03 compiler-specific alignment support guarantees that alignment in all cases. So there's no reason that should "make your program crash!". I've never seen an SSE/AltaVec/etc-based library that used compiler-specific alignment declarations that caused crashes with value parameters. And I've used quite a few.

So if they're having some kind of crash problem with this, then I would consider Eigen to be of... dubious merit. Not without further investigation.

Also, if an object is unsafe to pass by value, as the Eigen docs suggest, then the proper way to handle this would be to make the object non-copy-constructable. Copy assignment would be fine, since it requires an already existing object. However, Eigen doesn't do this, which again suggests that the developers missed some of the finer points of API design.

However, for the record, C++11 has the alignas keyword, which is a standard way to declare that an object shall be of a certain alignment.

Also, why is there no problem with returning such objects by value?

Who says that there isn't (noting the copying problem, not the alignment problem)? The difference is that you can't return a temporary value by reference. So they're not doing it because it's not possible.

like image 121
Nicol Bolas Avatar answered Oct 12 '22 23:10

Nicol Bolas


They could do this in C++11:

class alignas(16) Matrix4f
{
    // ...
};

Now the class will always be aligned on a 16-byte boundary.

Also, maybe I'm being silly but this shouldn't be an issue anyway. Given a class like this:

class Matrix4f
{
public:
    // ...
private:
    // their data type (aligned however they decided in that library):
    aligned_data_type data;

    // or in C++11
    alignas(16) float data[16];
};

Compilers are now obligated to allocate a Matrix4f on a 16-byte boundary anyway, because that would break it; the class-level alignas should be redundant. But I've been known to be wrong in the past, somehow.

like image 37
GManNickG Avatar answered Oct 13 '22 00:10

GManNickG