Before the edit, your concern that push_back()
was "too complex" wasn't clear. (It sounded like perhaps even you didn't like the name of the method...or something strange like that?)
I'll try to get to addressing the new issue raised. But I will reiterate that although you are using the standard library string
and vector
classes, your structures are not themselves getting the advantages of C++!
You don't have constructors, destructors, or methods. Those are the foundations of letting data objects "come alive" with "magic" behavior that lets clients of these classes write simpler, more abstract code. This is helpful even if your only "client" is just more of your own code!
Let's say before you had code like:
pio_parts pp;
pp.pio_name = "this string will be stored in the name";
pp.report.push_back(someReport);
pp.report.push_back(anotherReport);
If you add a constructor and a method to your structure, like this:
struct pio_parts {
string pio_name;
vector<report_specs> report;
pio_parts(string newName) {
pio_name = newName;
}
void addReport(report_specs newSpecs) {
report.push_back(newSpecs);
}
};
Then the code above gets nicer:
pio_parts pp ("this string will be stored in the name");
pp.addReport(someReport);
pp.addReport(anotherReport);
Though really, you've not done much than save yourself from having to know the name of the data member in pio_parts
to add to. Now you remember a method name instead. You save a little typing, but push_back()
was about as good.
HOWEVER if there were more related operations you need to do inside of addReport()
than just add to the vector, you now have a place to put all that code. That way the user of your class can not worry about whatever bookkeeping is necessary to add a report...they just ask that it be done! Also, since there's no call to push_back()
it's no longer necessary for whoever is calling addReport()
to know that the list is being stored in a vector.
I've deliberately not even bothered to try and scratch deeper into the specifics of references, copy-construction, smart pointers, member initialization syntax, or even class
vs struct
. It's too deep a language. Take a time out ASAP and carefully read this short paper by Bjarne Stroustrup that lays out that clear contrast in methodology:
Learning Standard C++ as a New Language
Now I'll try to get on to your other concern. First of all, you do not have to create a named instance of a variable in C++ to pass it to a function. You can rewrite:
sub_parts sb1;
interface[i].sb.push_back(sb1);
...as instead:
interface[i].sb.push_back(sub_parts ());
Not particularly useful in this case, as the object is constructed empty...so you just pushed something useless. But if your constructor took parameters that filled the object, it would be fine. You can even build up arrays like this:
How can I initialize an array of objects whose constructor require two or more arguments?
But if your constructor takes a hardcoded list (as yours seem to), then there's been a bit of a fly in the ointment. While C++ can initialize ordinary arrays with values you code in directly, passing the ordinary array loses its length information. A vector would be better, but initializing them with hardcoded values is clunky:
What is the easiest way to initialize a std::vector with hardcoded elements?
You can see that people had pretty much the same complaint you did about having to write:
std::vector<int> ints;
ints.push_back(10);
ints.push_back(20);
ints.push_back(30);
That post lists some of the workarounds, but bleeding edge compilers (probably not what you're using) support:
std::vector<int> ints = {10, 20, 30};
Once you have those, it makes it extremely easy to do your "nested" style constructions.
As a final note: you seemed on an earlier comment to concretely ask about raw arrays vs vectors. For your interface
you almost certainly want a vector. Here's a pitfall: using new xlsmain[100]
on a raw array requires to remember to do a delete[] interface
(and not just a regular delete interface
):
delete vs delete[] operators in C++
Bear in mind there is also no realloc in C++ anyway. So if that's why you were dynamically allocating it, forget about that idea.
You can save yourself from trouble like this by just making interface a vector. You will be able to resize it if you ever need to, and also avoid hard-coding a so-called "Magic Number" into your program.