Multiple Formats: Reading Working Routine From File
Avoid pointers

In this case, there seems to be no particularly good reason for your map to store pointers to the data instead of just storing the data directly. It'll simplify your code a bit if you just have it store something like a vector&lt;exercise&gt;. Alternatively, you could consider using a std::multimap&lt;std::string, Exercise&gt; (which has a similar effect).

Note that many people are likely to give advice more like: "avoid raw pointers". While that's good advice in itself, I prefer to avoid (explicit use of) pointers entirely if possible. If you find that you can't avoid using a pointer, then use a smart pointer. But if you can avoid using any sort of pointer at all, so much the better.

Distribution of responsibilities

You've defined an Exercise class (or struct), but all the responsibility for reading an Exercise from a file has been assigned to Routines. At least IMO, it would be better if an Exercise knew how to extract itself from a file, and a Routine just made use of that to read the exercises in a routine.

map data type

Right now, your Routines is basically just a map with an overload of operator&gt;&gt; to extract data and populate that map from the file. We don't need to define a new class just for that purpose though. map already uses a template to define the type of data it stores--we can just use that (and give it a name, if we like):

using routine = std::pair&lt;std::string, std::vector&lt;Exercise&gt; &gt;;


Putting those together we get extraction operators for routine and exercise that look something like this:

std::istream &amp;operator&gt;&gt;(std::istream &amp;in, Exercise &amp;e) {
    std::string temp;
    std::getline(in, temp);
    std::istringstream is(temp);
    std::getline(is, e.name, ',');
    is &gt;&gt; e.reps;
    if (is.peek() == ',') {
        is.ignore(1);
        is &gt;&gt; e.weight;
    }
    else
        e.weight = 0;
    return in;
}

std::istream &amp;operator&gt;&gt;(std::istream &amp;is, routine &amp;r) {
    std::getline(is, r.first, ',');
    int count;
    is &gt;&gt; count;
    is.ignore(1024, '\n');
    for (int i=0; i&lt;count; i++) {
        exercise e;
        is &gt;&gt; e;
        r.second.push_back(e);
    }
    return is;
}


So now we've restricted the messiness of reading an exercise correctly to a somewhat smaller area. A Routine just reads a name and a some number of Exercises.

With those in place, initializing a map of routines from a file can look something like this:

std::ifstream in("routines.csv");

std::map&lt;std::string, std::vector&lt;exercise&gt;&gt; routines {
    std::istream_iterator&lt;routine&gt;(in), {} };


Of course, if you really want to define your own complete class for Routine, you can do that--but I'd still keep the responsibility for reading an Exercise in an extractor specifically for an Exercise.