Reputation: 35
Suppose I do something like:
class A
{
public:
class B
{
public:
void SomeFunction1() const;
using atype = A;
};
using btype = B;
void SomeFunction2() const;
private:
B b;
};
Then I create an instance of class A and copy it:
A a;
A acopy = a;
Does that make the class A heavy, what I mean is, what happens in the background? I would hope that C++ doesn't really literally "consider" the definition of class B everytime I declare an instance of class A, I thin what happens in the background is that class B will be treated as a new definition under a namespace named A, so A::B is defined. My question is does defining a class inside a class (B inside A) create any overhead when declaring or copying the class A, or it's treated exactly as if B is defined outside?
Thank you everyone :)
Upvotes: 0
Views: 909
Reputation: 35
So I am the one asking the question, I have tested what @david dragilev implemented on Google Benchmark. Results attached, indeed the difference is very small. I can't say the outside version is faster but it theoritically (based on the numbers) is.
Results: https://quick-bench.com/q/sgwCs8kHfePvAaFeLe03uqmCsIo
Upvotes: 0
Reputation: 81
Both possibilities (B as nested class and B as external class) will yield exactly the same performance.
In fact, the compiler will generate the same assembly code in both cases.
B as external class:
https://godbolt.org/z/7voYGd6Mf
B as nested class:
https://godbolt.org/z/731dPdrqo
B is a member of A. Hence it resides in A's memory layout and B's constructor will be called every time you constructor/copy A. The introduced overhead depends on B implementation, but it will be identical in both cases (B nested and external class),
Upvotes: 2
Reputation: 180303
C++ is a compiled language. We generally assume that the computers used to compile C++ source code are powerful enough. Compilers may reasonable use Gigabytes in the process of compiling an executable.
So when we say that something is "heavy", we usually mean that it's heavy at runtime. The runtime environment for a C++ program may well be a coffee maker or a fridge.
Things like name lookup in nested scopes are pure compile-time actions, and do not have any runtime impact. And modern compilers are smart enough to inline the default methods here, so there's no runtime overhead in calling members.
Upvotes: 0
Reputation: 1644
My own opinion is:
B
class could be fully merged with A
class most of the time.B
if required by A
, and never ever used elsewhere, it can be defined out of A
. Constructors are your friends to "force" some associations - delete the default constructor, for example.A
, it doesn't change anything regarding deep copy.B
directly through A
, it's a design flaw - move these functions from B
to A
instead.So I really don't see, apart "sparing" a header file, what you can "gain" by declaring a class within a class...
For my part, I would prefer:
B
, if it isn't required publicly.A
either permanently (move the source code), or use wrappers to the PIMPL object.B
instance, change the unique_ptr
for the PIMPL object to a shared_ptr
instead. Take care of deep copy.It's usually WAY more efficient, hides perfectly the B
code if required (don't even need to export it from a DLL, for example), you won't recompile B
at all when changing A
and you can change how B
work without even breaking your A
API.
Upvotes: 0