14

I don't understand why adding a forward declaration for a class changes a size of its pointer to member type

#include <iostream>
using namespace std;

int main()
{
    //struct CL;
    //cout<<sizeof(int (CL::*)())<<endl; 
    struct CL{};
    cout<<sizeof(int (CL::*)())<<endl;
}

output VS2013:
4

But if I uncomment the first two lines in main(), then the output is different:
16
16

So, only a simple adding a forward declaration before a definition of struct CL increases a size of a pointer to member of CL. Why? I know that a size of member function pointer depends by structure of a type (e.g. virtual functions and base classes may increase it), but why can the sizeof operator be applied to a pointer to member of an incomplete type? Or it can't? I have not found it in the Standard

5
  • struct CL{} is definitely a local class in the function. Not sure about struct CL; Anyways, it looks like a bug of msvc Commented Jun 18, 2015 at 18:54
  • 1
    @DieterLücking struct CL; is a forward-declaration of a local class in this case, see [basic.scope.pdecl]p7.1 Commented Jun 18, 2015 at 18:58
  • See also: social.msdn.microsoft.com/Forums/vstudio/en-US/… (via stackoverflow.com/a/13881429 ) Commented Jun 18, 2015 at 19:01
  • @dyp Is that another reason to hate msvc? Commented Jun 18, 2015 at 19:05
  • @DieterLücking It is another reason to set it up properly ;) Just like -Wall -Wextra -pedantic -std=c++?? in g++, you need to deactivate language extensions in cl, possibly deactivate comdat folding, and force it to use the same size for all member pointers. Commented Jun 18, 2015 at 19:08

1 Answer 1

12

The MSVC compiler uses different sizes for pointers to member functions as an optimization. This optimization violates the Standard. Kudos to Igor Tandetnik mentioning reinterpret_cast in a MSDN form post, [expr.reinterpret.cast]p10

A prvalue of type “pointer to member of X of type T1” can be explicitly converted to a prvalue of a different type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types. The null member pointer value is converted to the null member pointer value of the destination type. The result of this conversion is unspecified, except in the following cases:

  • converting a prvalue of type “pointer to member function” to a different pointer to member function type and back to its original type yields the original pointer to member value.

So there's a roundtrip guarantee, this effectively forces conforming implementations to use the same size for all pointer to member function types.


The MSVC optimization is performed if the /vmb switch is set. For the case of single inheritance, the optimised pointer to member function requires only a void*-sized storage, see The Old New Thing: Pointers to member functions are very strange animals.

If you only forward-declare the type CL and then form a pointer-to-member function, the optimization hopefully is deactivated (I could not find any documentation on that, unfortunately). Otherwise, you might get inconsistent sizes before and after the definition of CL.

By the way, you can get inconsistent sizes for enumerations in VS2010, if you forward-declare them without specifying an underlying type and later explicitly define the underlying type for the definition of the enum. This works only with language extensions activated.

Sign up to request clarification or add additional context in comments.

Your Answer

Draft saved
Draft discarded

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.