1

I recently decided to export some of my functions to a static library (.lib). I also decided not to give the complete header files to the Users. I kept private and protected variables and methods out of it, as the end-users should not use them and should not have to include other headers for Class declarations.

Unexpectedly I ran into heap-corruption errors when creating instances of the Classes which I exported to the static lib.

This is my original header file:

// Original Header File
class CODBCHelper
{
public:
    CODBCHelper();
    virtual ~CODBCHelper();

public:
    std::vector<UserData> getUserInformation();

private:
    SQLHENV     m_henv;
    SQLHDBC     m_hdbc;
    SQLHSTMT    m_hstmt;
};

Then I decided to take the private variables out, so that users of my .lib do not abuse them and do not have to include unnecessary SQL Header files:

// Minimized Header File
class CODBCHelper
{
public:
    CODBCHelper();
    virtual ~CODBCHelper();

public:
    std::vector<UserData> getUserInformation();
};

I noticed that the sizeof Operation returns different values depending from where it is called.

Called in the .lib:

int size = sizeof(CODBCHelper);
// size is 12

Called in the linking project:

int size = sizeof(CODBCHelper);
// size is 1

Doing the following code in my linking project then causes a heap corruption (which happens probably because of wrong size calculations):

CODBCHelper* helper = new CODBCHelper;

Doing something like

class CODBCHelper
{
[...]
private:
    char padding[12];
}

would solve the problem, but i think its really bad behavior and not maintainable at all.

So is there any way to tell the compiler how big the real Object (from the linked library) is going to be? Or is there any easy way of hiding declarations in header files that are not needed by users?

Vinz
  • 3,030
  • 4
  • 31
  • 52

3 Answers3

2

I don't see how "hiding unimportant members" is connected to removing them from class definition.

I guess, that you wanted to eliminate unnecessary dependencies from your code. This is a good technique - it reduces compilation time, makes your code more portable between different versions and much more.

The thing is, that you changed your class completely. If it was designed to have three private members:

SQLHENV     m_henv;
SQLHDBC     m_hdbc;
SQLHSTMT    m_hstmt;

you cannot just remove them. This is not what "hiding implementation details" means.

Or is there any easy way of hiding declarations in header files that are not needed by users?

What you want is to use PIMPL Idiom:

//Minimized header file
class CODBCHelper
{
public:
    CODBCHelper();
    virtual ~CODBCHelper();

public:
    std::vector<UserData> getUserInformation();

private:
    struct InternalData;
    InternalData* m_internal_data;
};

Then, in your .cpp file:

struct CODBCHelper::InternalData
{
    SQLHENV     m_henv;
    SQLHDBC     m_hdbc;
    SQLHSTMT    m_hstmt;
};

Now you change your implementation to use m_internal_data instead of each component separately. This is especially profitable if your software will be updated - it forbids clients to create code, that depends on implementation details of your types.

You may also want to read point 2. and/or 4. of this answer.

Community
  • 1
  • 1
Mateusz Grzejek
  • 11,698
  • 3
  • 32
  • 49
  • I guess you suggest using one and the same header file then for the .lib and linking projects? Because `InternalData* m_internal_data` increases the size of the class by 4 bytes – Vinz May 14 '15 at 18:45
  • And...? Classes have members, that's quite normal. Why is this wrong for you? – Mateusz Grzejek May 14 '15 at 19:06
  • Yes you are right. I was just making sure to use the header file in both projects now. Thanks for showing a simple way of doing this with the encapsulation of the internal data ;) – Vinz May 14 '15 at 19:25
  • Header files should be identical in both cases, that is: the same header, that is used for building your library should be delivered to user. Only certain defines (export specifiers, etc...) may change. This is how it is done in every known library out there :) – Mateusz Grzejek May 14 '15 at 20:24
1

You could expose interfaces instead of classes + a factory class. That way your users don't see the construct of your actual classes and everything works fine.

For example, your users get this:

class ICODBCHelper
{
public:
    virtual ~ICODBCHelper();

public:
    virtual std::vector<UserData> getUserInformation();
};

class MyFactory
{
public:
    ICODBHelper *CreateCODBHelper();
}

and you implement this:

class CODBCHelper : public ICODBHelper
{
public:
    CODBCHelper();
    virtual ~CODBCHelper();

public:
    std::vector<UserData> getUserInformation();

private:
   SQLHENV     m_henv;
   SQLHDBC     m_hdbc;
   SQLHSTMT    m_hstmt;
};
Amit
  • 45,440
  • 9
  • 78
  • 110
  • Goodness... going for factories to solve simple problem with hiding implementation details? Really...? Not to mention overhead of virtual functions, when they may not be useful in this case. – Mateusz Grzejek May 14 '15 at 18:39
  • Still a nice idea though. Thanks for your contribution! – Vinz May 14 '15 at 19:24
0

Create an abstract class that is public with pure virtual methods, no data. Then create a factory/accessor to instantiate/access the actual object in your library code that is actually a derived/concrete class of the abstract class.

franji1
  • 3,088
  • 2
  • 23
  • 43