C++ Readonly Structs – Efficient Passing Techniques

cdesign

In this particular problem I am having, I am not sure of the proper way to deal with readonly structs, passed to class constructors as a parameter when I want to store the data in the struct, in the class.

For example, I have a struct which contains some settings

typedef struct s_MyStruct{
    int x;
    int y;
    std::string name;
    //... arbitrarily many properties.  
} MyStruct;

and I have a class which takes an instance of MyStruct as a parameter in the constructor

class MyClass {
public:
    MyClass(MyStruct settings){
        //I would like to store the data in settings in the class
    }
}

The class is instantiated in a function like this:

void theFunction(){

    MyStruct m_settings { //.. initialization logic }

    MyClass *mClass = new MyClass(m_settings);

    //a reference mClass is passed somewhere so we can access it later
}

So I know when "theFunction" leaves scope it will deallocate the m_settings variable. I was thinking I could make a copy of the struct, or perhaps store copies of all of the variables. Or maybe instead or initializing the struct on the stack I just do a heap allocation and clean up the struct in the class destructor. I don't know the proper design for this sort of message passing in C++ I am not used to manual memory management coming from a managed language background. What is the standard way to handle this struct full of settings?

Best Answer

Preliminary remark

In C++ a struct is in fact a class with all members being public. So you could define it more simply:

struct MyStruct{
    int x;
    //... etc.  
};   // no need for typedef here !  

Pass parameter by const reference to the constructor ?

This being said, the way you use it in your constructor makes in fact a copy of your struct (into the parameter). If you're worried about the size of the struct when it's passed as argument, you could define your constructor as:

class MyClass {
public:
    MyClass(const MyStruct& settings) {  // pass a const reference
        ...
    }
};  // ending semi-colon please ;-) ! 

Want to keep a local copy of the initialisation parameters ?

If you then want to keep a copy of all these parameters in your constructed object, just use a mem-initializer:

class MyClass {
    MyStruct m_settings;   // local copy of parameters
public:
    MyClass(const MyStruct& settings) : m_settings(settings) {  
        ...
    }
};

Don't take unnecessary risk with manual memory allocation

Of course, you could do as you thought: allocate a MyStruct object on the free store and pass a pointer. It's technically working, but this is not the way to go in C++. You risk memory leaking in case of unexpected errors, or if you do'nt take care of it in the destructor. You'd risk shallow copies when copying the struct if you don't provide a copy constructor and an assignment operator. So you'd need to take care of the rule of 3 whereas in the approach I proposed you you can safely benefit from default copy constructor, copy assignment and destructor.

If you'd nevertheless wanted to go this way and take care of all this, consider at least use of a shared_ptr<MyStruct> instead of a raw MyStruct* pointer.

Related Topic