user3511860
user3511860

Reputation: 17

C++ struct initialization

I have the following struct declaration in somecode.h:

    struct MySt
    {
        MySt( const char * m, const char * gm ):
            firstSen(m),
            secondSen(gm)
        {
        }

        std::string firstSen;
        std::string secondSen;
    };

Here is the code in somecode.cpp:

        std::vector<MySt> dataSen;

        char * cp = trim(buff);
        std::vector<std::string> tokens;

        getTokens( cp, tokens );

        if(tokens.size() == 2 )
        {

            dataSen.push_back( MySt(tokens[0].c_str(), tokens[1].c_str() ));
        }

This code works. My question is: This type of MySt initialization, is it stack or heap, is it dynamically or statically allocated? Thnx.

Upvotes: 1

Views: 127

Answers (2)

RyanP
RyanP

Reputation: 1918

There is a lot going on here.

dataSen is a vector which means that it has a small amount of space on the stack to store a pointer to its storage as well as some overhead stuff (like size, etc) but everything it stores is on the heap via an allocation that it manages.

std::string, the type stored by dataSen, actually has a small amount of data being stored inside your vector (which again, is on the heap) and then creates a heap allocation of it's own for it's data. (There is a small string optimization that can take place, but that's beyond the scope of this).

So you read things into a tokens vector, which stores the data as strings. The storage for the strings is on the heap (through vector's heap allocation) as is the storage within the string for the actual characters (through a heap allocation managed by the string).

Then you use c_str() to get a const char* reference from the each string to create a temporary MySt (which has create two new strings, initialized by the const char*'s). This temporary is then copied into the vector, which means it is stored on the heap managed by the vector, with each of the strings data being stored on the heap through different allocations managed by string.

Now... none of that might actually be true because the optimizer can do lots of tricks, but that's what you are requesting be done.

Coincidentally, if you use emplace_back(const char*, const char*) instead of push_back(MySt(...)) you would construct it in place instead of making a temporary and moving.

Additionally, if you added a constructor for MySt that took std::string&& values you could move the strings you have already created into MySt to avoid casting to a const char* and then creating another string from that.

Edit for your comment:

struct MySt
{
    // existing constructor, creating strings from const char*
    MySt( const char * m, const char * gm ):
        firstSen(m),
        secondSen(gm)
    {
    }

    // constructor copying string inputs
    MySt( const std::string& m, const std::string& gm) :
        firstSen(m),
        secondSen(gm)
    {
    }

    // constructor moving existing strings (strings from calling code
    // will be in an unusable state other than to re-assign them to
    // something new... but it will take the allocated heap from the
    // existing strings as to avoid making another heap allocation)
    MySt( std::string&& m, std::string&& gm) :
        firstSen(std::move(m)),
        secondSen(std::move(gm))
    {
    }

    std::string firstSen;
    std::string secondSen;
};

Then use...

getTokens( cp, tokens );

if(tokens.size() == 2 )
{
    // to copy...
    dataSen.emplace_back( tokens[0], tokens[1] );

    // or to move...
    dataSen.emplace_back( std::move(tokens[0]), std::move(tokens[1]) );
}

Upvotes: 2

user3099493
user3099493

Reputation:

  • If you declare objects globally or as static local, they are allocated statically.
  • If you declare in a block, they are allocated on the stack.
  • If you use new keyword, they are allocated on the heap.
  • Elements of STL containers are also stored on the heap.

Upvotes: 0

Related Questions