Simple CFG parser in C++
Use std::move where appropriate

When you take an object parameter by value with the intent of copying it, use std::move to take advantage of move semantics if the object supports it. This is the case with std::string. But be aware that after moving a string, the original will be left empty, so it is better to restructure CFG::Init to something like the following:

bool CFG::Init(std::string filename)
{
    if (filename.empty())
    {
        return false;
    }

    std::ifstream fileIn(filename);
    if (!fileIn.is_open())
    {
        return false;
    }

    m_buffer &lt;&lt; fileIn.rdbuf();

    m_cfgFilename = std::move(filename);
    // 'filename' is now empty. It's contents were take by 'm_cfgFilename'

    Parse();
    return true;
}


It's probably also better to only assign m_cfgFilename at the end, so you don't set that member if you fail to open the file, but that might not be the behaviour you want. Otherwise, you can still move filename to the member string at the top and then use the member string instead.

Also notice that I've renamed the ifstream t in my example. Single letter names are pretty bad, with the exception of a few specific places like in for-loop counters.

CFG::Parse()

This line here is overly complicated:


if (!line.empty() &amp;&amp; line.compare(0, commentKey.length(), commentKey))
{
    ...
}



std::string has the == operator overloaded, so you can compare two strings like you would compare a number. But since a comment is any line starting with '#', you might as well just test line[0].

Going further, it's better to avoid deep nesting when you can. Just continue if the condition is true.

if (line.empty() || line[0] == '#')
{
    continue;
}


Better string trim

You can cut down the size of your main reading loop by introducing a small helper function to trim the string. Having such simple utility function at hand can also be useful in other places. You can find a couple nice samples in here. This one in particular might be faster, since it doesn't create the temporary stringstream.

While you are at it, go ahead and turn that to-lowercase transform into a separate function as well:

inline std::string lowercase(std::string str)
{
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
    return str;
}


A tiny optimization

This is arguably a micro-optimization, but at scale it might have impact. If you move the declaration of your vector seglist and the temporary segment string to the top level of the function, that will avoid recreating the objects at each iteration of the loop. You just have to clear() them at the start of the loop. vector and string might be allocating and freeing dynamic memory on construction/destruction, so if they are only constructed once and just cleared, the memory stays allocated until the end of the function.

The downside of doing this is that you go against the recommendation of declaring variables as close as possible to the first point of usage, so it might not be worth it. Since this is a loop with potential hot code in it, might be interesting.