开发者

Memory structure of a function-only object?

Let's say we have a class that looks like this:

class A 
{ 
    public:
        int FuncA( int x );
        int FuncB( int y );

        int a;
        int b;
};
开发者_StackOverflow中文版

Now, I know that objects of this class will be laid out in memory with just the two ints. That is, if I make a vector of instances of class A, there will be two ints for one instance, then followed by two ints for the second instance etc. The objects are POD.

BUT let's say the class looks like this:

class B
{ 
    public:
        int FuncA( int x );
        int FuncB( int y );
};

What do objects of this class look like in memory? If I fill a vector with instances of B... what's in the vector? I've been told that non-virtual member functions are in the end compiled as free functions somewhere completely unrelated to the instances of the class in which they're declared (virtual function are too, but the objects store a vtable with function pointers). That the access restrictions are merely at the semantic, "human" level. Only the data members of a class (and the vtable etc.) actually make up the memory structure of objects.

So again, what do objects of class B look like in memory? Is it some kind of placeholder value? Something has to be there, I can take the object's address. It has to point to something. Whatever it is, is the compiler allowed to inline/optimize out these objects and treat the method calls as just normal free function calls? If I create a vector of these and call the same method on every object, can the compiler eliminate the vector and replace it with just a bunch of normal calls?

I'm just curious.


All objects in C++ are guaranteed to have a sizeof >= 1 so that each object will have a unique address.

I haven't tried it, but I would guess that in your example, the compiler would allocate but not initialize 1 byte for each function object in the array/vector.


As Ferruccio said, All objects in C++ are guaranteed to have a size of at least 1. Mostly likely, it's 1 byte, but fills out the size of the alignment, but whatever.

However, when used as a base class, it does not need to fill any space, so that:

class A  {} a;    // a is 1 byte.
class B  {} b;    // b is 1 byte.
class C  { A a; B b;} c; // c is 2 bytes.
class D : public A, B { } d;  // d is 1 byte.
class E : public A, B { char ee; } e;  // e is only 1 byte


What do objects of this class look like in memory?

It's entirely up to the compiler. An instance of an empty class must have non-zero size, so that distinct objects have distinct addresses (unless it's instantiated as a base class of another class, in which case it can take up no space at all). Typically, it will consist of a single uninitialised byte.

Whatever it is, is the compiler allowed to inline/optimize out these objects and treat the method calls as just normal free function calls?

Yes; the compiler doesn't have to create the object unless you do something like taking its address. Empty function objects are used quite a lot in the Standard Library, so it's important that they don't introduce any unnecessary overhead.


I performed the following experiment:

#include <iostream>

class B
{ 
    public:
        int FuncA( int x );
        int FuncB( int y );
};

int main()
{ 
    std::cout << sizeof( B ) ;
}

The result was 1 (VC++ 2010)

It seems to me that the class actually requires no memory whatsoever, but that an object cannot be zero sized since that would make no semantic sense if you took its address for example. This is borne out by Ferruccio's answer.s


Everything I say from here on out is implementation dependent - but most implementations will conform.

If the class has any virtual methods, there will be an invisible vtable pointer member. That isn't the case with your example however.

Yes, the compiler will treat a member function call the same as a free function call, again unless it's a virtual function. Even if it is a virtual function, the compiler can bypass the vtable if it knows the concrete type at the time of the call. Each call will still depend on the object, because there's an invisible this parameter with the object's pointer that gets added to the call.


I would think they just look like any objects in C++:

  • Each instance of the class occupies space. Because objects in C++ must have a size of at least 1 (so they have unique addresses, as Ferruccino said), objects that don't specify any data don't receive special treatment.
  • Non-virtual functions do not occupy any space at all in a class. Rather, they can be thought of as functions like this:

    int B_FuncA(B *this, int x);
    int B_FuncB(B *this, int y);
    

If this class can be used by other .cpp files, I think these will become actual class instances, not regular functions.

If you just want your functions to be free rather than bound to objects, you could either make them static or use a namespace.


I've been told that non-virtual member functions are in the end compiled as free functions somewhere completely unrelated to the instances of the class in which they're declared (virtual function are too, but the objects store a vtable with function pointers). That the access restrictions are merely at the semantic, "human" level. Only the data members of a class (and the vtable etc.) actually make up the memory structure of objects.

Yep, that is usually how it works. It might be worth pointing out the distinction that this isn't specified in the standard, and it's not required -- it just makes sense to implement classes like this in the compiler.

So again, what do objects of class B look like in memory? Is it some kind of placeholder value? Something has to be there, I can take the object's address

Exactly. :) The C++ standard requires that objects take up at least one byte, for exactly the reason you say. It must have an address, and if I put these objects into an array, I must be able to increment a pointer in order to get "the next" object, so every object must have a unique address and take up at least 1 byte. (Of course, empty objects don't have to take exactly 1 byte. Some compilers may choose to make them 4 bytes, or any other size, for performance reasons)

A sensible compiler won't even make it a placeholder value though. Why bother writing any specific value into this one byte? We can just let it contain whatever garbage it held when the object was created. It'll never be accessed anyway. A single byte is just allocated, and never read or written to.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜