Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I force the compiler-generated copy constructor of a class to *not* be inlined by the compiler?

Alternate question title would be: How to explicitly have the compiler generate code for the compiler-generated constructors in a specific translation unit?

The problem we face is that for one code path the resulting -- thoroughly measured -- performance is better (by about 5%) if the copy-ctor calls of one object are not inlined, that is if this constructor is implemented manually. (We noticed this because during code-cleanup the superfluous explicitly implemented copy ctor of this class (17 members) was removed.)

Edit: Note that we have checked the generated assembly code and have made sure that the inlining and code generation is happening as I describe for the two different code versions.

We face now the choice of just dropping the manual copy-ctor code back in (it does exactly the same as the compiler generated one) or finding any other means of not inlining the copy ctor of this class.

Is there any means (for Microsoft Visual C++) to explicitly instantiate the compiler generated class functions in a specific translation unit or will they always be inlined in each translation unit where they are used? (Comments for gcc or other compilers are also welcome to get a better picture of the situation.)


Since the first 2 answers show some misunderstanding: The compiler generated class functions are only generated by the compiler itself if they are neither declared nor defined by the user. Therefore no modifiers whatsoever can be applied to them, since these function do not exist in the sourcecode.

struct A {
  std::string member;
};

A has a default and copy ctor, a dtor and a copy operator. Neither of these function can be modified via some declspec because they do not exist in the code.

struct B {
  std::string member;
  B(B const& rhs);
};

B now has a user supplied copy ctor and the user has to implement it. The compiler will not generate code for it.


Some more background for the doubters :-) ...

This code is compiled using MS Visual C++, but it is linked for an embedded(-like) (realtime) system. Performance was measured by taking timings on this system and I therefore think the guys who took the timings will have some decent numbers.

The test was performed by comparing two code versions where the only difference was the inline vs. the not-inline copy ctor of this one class. Timings with the inlined code were worse by about 5%.


Further checking has revealed that I was mistaken in one point: The compiler will generate separate functions for complex copy constructors. It will do this on its own discretion and it also depends on the optimization settings. So in our case the compiler is doing the wrong thing in our specific circumstances. From the answers so far it does not appear we can tell the compiler otherwise. :-(

like image 915
Martin Ba Avatar asked Oct 06 '10 08:10

Martin Ba


People also ask

Is copy constructor automatically created by compiler?

In C++, the compiler automatically generates the default constructor, copy constructor, copy-assignment operator, and destructor for a type if it does not declare its own. These functions are known as the special member functions, and they are what make simple user-defined types in C++ behave like structures do in C.

What is the right way to declare a copy constructor of a class if the name of the class is my class Mcq?

Explanation: The syntax must contain the class name first, followed by the classname as type and &object within parenthesis. Then comes the constructor body.

Does compiler provided copy constructor by default?

In C++, compiler created default constructor has an empty body, i.e., it doesn't assign default values to data members. However, in Java default constructors assign default values. The compiler also creates a copy constructor if we don't write our own copy constructor.


2 Answers

$12.1/5- "An implicitly-declared default constructor is an inline public member of its class.".

So there is nothing much we can do. The implcit constructor has to be an inline. Any other behavior in this regards would probably be an extension

Having said that,

It is likely that your manual copy constructor (which you removed during code cleanup) was doing the right thing. As an example, if one of the members (out of 17) in your class is a pointer member, it is likely that the manual copy constructor took care of deep copy(and hence took a performance hit).

So, unless you carefully review your manual copy constructor, don't even think of removing it and relying on the (potentially buggy) implicit copy constructor (in your context)

like image 104
Chubsdad Avatar answered Oct 27 '22 02:10

Chubsdad


I highly doubt inlining has anything to do with it. If the compiler inlines the compiler-generated copy ctor, why wouldn't it also inline the explicitly defined one? (It is also unusual that the compiler's optimization heuristics fail so badly as to make inlined code 5% slower)

Before jumping to conclusions,

  • check the generated assembly to verify that the two versions actually do the exact same thing (and in the same order, using the same assembly and so on, since otherwise that might be the source of your performance difference)
  • check that the compiler-generated one actually is being inlined, and the manually defined one is not.

If that is the case, could you update your question with this information?

There is no way in C++ to indicate if a compiler-generated function should or shouldn't be inlined. Not even vendor-specific extensions such as __declspec(noinline) will help you there, since you're explicitly handing over all responsibility for the function to the compiler. So the compiler chooses what to do with it, how to implement it and whether or not to inline it. You can't both say "please implement this function for me", and at the same time "please let me control how the function is implemented". If you want control over the function, you have to implement it. ;)

In C++0x, it may be possible (depending on how these vendor-specific extensions interact with functions declared as = default).

But again, I'm not convinced that inlining is the issue. Most likely, the two functions just result in different assembly code being generated.

like image 24
jalf Avatar answered Oct 27 '22 02:10

jalf