C++ approach to handling collections

Hi,
Thanks for the help in advance.
So as a learning project I'm building a customer information system but I'm coming at it in a way I was never allowed to come at it in business. Rather than a customer record with names, phone numbers, address, etc, I'm coming at it as a collection of collections (to use C# or Java terms)

So.. I have a phone number object that I want to roll up into a collection of phone numbers for the person, an address object that will roll up into a collection of addresses for that person. Even a name object that holds just one word (name part) and rolls up into a collection of words that make up the various parts of a full name.

I know from C# and Java how to build the inheritance based collection object to inherit my simple objects into but I'm not here to learn to code C# or Java in C++, I'm here to learn how I should approach this in C++ and the language characteristics that I need to learn to do it.
I've seen terms like "Set" and "template" tossed around on the net that clued me into the idea that there may be a better approach I should be asking about if I really want to learn to code C++.

My C++ level is really beginner (basic objects, accessors, etc). I'm hoping to learn how to code in C++ PROPERLY. I just don't know enough to know where I should be focusing for this little challenge.

Thank for your coaching


C++ is a nasty language. It is also by far my own preferred language.

While similarities may seem obvious at a glance with Java and C#, there are serious differences.

The benefit is performance, size and flexibility. The detriment is that it takes a far more disciplined approach to keep from snaring oneself in traps. The underlying C language is still there, and it is this fact which gives C++ great power, and great pitfalls.

You are going to need a reading list, starting with a beginner's guide. Stroustrup has a good one, but many find it difficult to follow (if comments and questions inform on that point). The book is particularly good at training the new student to avoid the pitfalls. It is better at being such a guide than a gentle tutor, but it was also what Stroustrup used as a textbook for teaching C++.

Your question is most specifically answered by the standard library containers. Some you may find applicable are vector, list, deque, map and their related materials.

The term "template" in C++ relates, loosely, to C#'s generics. The standard containers are themselves template classes.

However, since you're at such an early stage of study, the containers and the more advanced standard library may have to wait until you're past the constructor/destructor cycle of C++ objects. That is a key difference between C++ and C# (and Java) that must be clearly understood before continuing, or you will get nowhere in C++.

The topic is named "RAII", which Stroustrup regrets as a name. It refers to a design pattern where any resource to be acquired becomes the initialization of an owning object, which takes the responsibility of releasing that resource (automatically) upon destruction. To most C++ programmers this is a feature missing from both Java and C# (and arguments ensue from there from C# and Java proponents). However, since C++ retains C's "level" of access to the hardware and underlying operating system primitives, it is a requirement which C# and Java can do without to some degree.

RAII is first met, for most, by the string class from the standard library (when compared to the way string data is handled in C). It is informative to know how C handles string data (it promotes appreciation for the string class), but not required. RAII may not be discussed when studying the string class, but the fact you don't have to manually allocate and free memory is because the class implements that for you, which is a demonstration of RAII.

The stream classes are another point where RAII is met, and may not be described, early in study. In C, a file that is opened must be closed when finished. Failure to do so results in a leak of available file handles. A subtle bug often results from multiple paths out of the code which uses the file, where one path fails to close the file handle. A stream class makes it irrelevant, because the class, through the RAII design paradigm, closes the file automatically.

C++ has evolved so much over the years that the learning curve is much longer now than ever, but the power and reliability of well written code is unmatched by other languages.

You might start by visiting "stroustrup.com" - from which you'll find links to excellent reading materials, from the inventor of the language.

Books by Sutter and Josuttis are always good, but few are for beginners.
Last edited on
Yes, I've had the hard copy special edition of "The C++ Programming Language" book by Stroustrup since 2011 when I bought it. The term "RAII" doesn't appear in the table of contents or in the index, so no clue what your referring to. Meyers also had a reasonably good book that I grabbed in it's 12th printing in 2012 as well as a number of Osbourne books on the topic. I have many more I could name but they're on my other book shelf in the spare room, not sitting next to me right now. I'm also a pilot.. Books provide knowledge... experience provides skill. There are some things that simply aren't in books.

Yes I am was very relieved to be rid of malloc() when I heard of it back in the late 90's when I was trying to get into C++ back then. I was a little alarmed to hear of more memory leaks in the function call some years later and curious how it was leaking memory if you no longer needed to use it?!?

In reference to you recommendation that I study string implementations in C so that I can better appreciate them, I would suggest its not much different than my 4 years in 6809E assembler and 2 years in 8088 assembler or 6 month revisit in 2015 via VS2015 C++ compiler. There I've always been dealing with the data at register level. You see, when I started, the world wasn't as advanced as today.. C++ didn't exist, especially for home computers back in 1982. So to do low level work I had to resort to assembler, something I noted in my profile.
Mind you, I did learn C back in the 90's when working with the Windows SDK and message loops. I was thankful to finally see MFC show up although I'm not a fan of code generators.

We are learning in a bottle, especially now with COVID-19. We have no peers to bounce ideas off of or to discuss new concepts with so I tend to use forums for that, perhaps that's an error on my part. Perhaps the question I should have asked is;

Perhaps a better way to approach the question is;
I've read in places that simply creating an instance of my object and turning it a list or container like Vector, List or Set via STL isn't the best approach. If it is, I can do those all day long. I'm not asking you to teach me how to make an collection, I'm asking what's the best approach so I can go off and read up on it.

I have a data item.. I want to have a list or collection of data items. Do I just Vector<MyDataItem> or should I consider something else that is more inline with the way I should be writing C++ code.
'

Last edited on
TheManx wrote:
I'm hoping to learn how to code in C++ PROPERLY.

There are two online tutorials you might want to take a peek at. The C++ tutorial here at cplusplus: http://www.cplusplus.com/doc/tutorial/

And "Learn C++": https://www.learncpp.com/

The tutorial here hasn't been updated since C++14 was finalized (it might even have stopped with C++11), so is outdated. Learn C++ is being updated all the time.

I personally suggest using Learn C++ if learning online is helpful.

Stroustrup's "The C++ Programming Language" is more of a reference for experienced C++ programmers, not a book for learning the language.

His 2nd edition of "Programming Principles and Practice Using C++" is more of a teaching tool. Derived from his lectures for a first year university course. With C++11 and C++14 material.

RAII is mentioned in PPPC++.
Thanks so much Furry Guy. That's very helpful!
I did grab a Wrox book some time ago by Marc Gregoire entitled "Professional C++" that is incredibly detailed. The book is massive and an easy read. I even exchanged emails with the author at one point.

Truth is I've learned C++ numerous times over my 35+ years in the industry and have a ridiculous number of C and C++ books spanning decades but I kept getting pulled away from the language for work. I wanted to get more in depth and I learn best with sample projects through which I study techniques and solutions. Yours is the second posting recommending external resources so this forum seems to be more of an RTFM forum.

Thanks, I'll take a look at the link to see what it has to offer.
We have a similar history. My first programming efforts were in the late 70's.

The tutorials Furry Guy mentions are a good place to look. The subject is vast, so offering an example here may not do as well.

That said, consider:

std::vector< A > v;

Where A is a class with a few members. One might do:

A i {};

or

A i { 1 };

if A's constructor took a 1 as a parameter.

That could be, in older C++:

A i( 1 );

In either event, i is allocated on the stack, assuming this is in a function.

It is possible to:

v.push_back( i );

Technically this copies the content of i into an instance owned by v.

That said, in modern optimized compilers there may not actually be a copy. It is technically implied, of course, but to put this in an oversimplified colloquialism, the compiler generates code based on what was meant, not precisely what was written.

So, this is a valid way to build up a container, with caveats.

The content of A may not allow copies. That depends on how A is built.

In other contexts, it may be that a copy is automatically generated, especially in a naive or incomplete class, but it may be inappropriate (or wrong).

For example, if A were to use raw pointers to store allocated memory, a copy would assume it, too, owns that memory. Both might delete the same memory, and the second one would (or should) be a crash.

If A held such an allocated object via shared_ptr, that would be safer, but it might not be the intent. In such a context, when the object held by the shared_ptr is modified, both the copy (held in the container) and the original (on the stack) would "see" that change.

As such, for these and other contexts, it may be required to write a copy constructor and assignment operator which deals with these issues according to a strategy. Say, for example, finding a raw pointer to a string would mean the copy should allocate it's own string and copy the content.

Using a string class, of course, would alleviate that concern.

However, it may be that you want a container to hold new objects, not copy them. There can be:

std::vector< std::shared_ptr< A >> v;

In this context, v stores shared_ptr's to an A, not an A itself. To use it, you'd first have to create such a thing:

auto i = std::make_shared< A >( 1 );

Here, i ends up being a shared_ptr, holding a new A allocated from the heap.

v.push_back( i );

Here, v copies the pointer, both sharing the ownership of the A created by make_shared.

Since i is temporary, it will disappear soon afterwards, but the allocated object will be retained in v using the shared_ptr.

This is illustrative of using shared_ptr without discussing the likely intent that threads may be involved (because sharing containment using shared_ptr is often justified due to threaded development work). There are other reasons for using shared_ptr, but it was way overused when first introduced.

vectors can be sorted by the sort algorithm, which may require that you build and supply a comparison function or object.

maps are usually implemented as trees which also sort, but have much different use characteristics. That is the subject of algorithms and data structures, a subject aside C++ (as it applies to many languages), but is a required understanding so as to facility intelligent selection among the container options in the standard library (or the decision to create a container for unusual situations not supported by the standard library).

It's late, so I may have typos in the code line examples above.


> I have a phone number object that I want to roll up into a collection of phone numbers for the person

>> I want to have a list or collection of data items. Do I just Vector<MyDataItem>

Yes; something along those lines. For instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <string>
#include <iostream>
#include <vector>

// I have a phone number object
struct phone
{
    std::string number ;

    unsigned long long to_ullong() const { return std::stoull(number) ; } // may throw

    // etc.

    // that I want to roll up into a collection of phone numbers for the person,
    using collection = std::vector<phone> ;
};

struct person
{
    std::string name ;

    // collection of phone numbers for the person
    phone::collection phone_numbers ;

    // etc.
};

int main()
{
    // create a person with a name and a collection of three phone numbers
    person per { "name", { {"123"}, {"567"}, {"890"} } } ;

    per.phone_numbers.push_back( {"9999"} ) ; // add another phone to the collection

    // print out the info
    std::cout << "name: " << per.name << '\n'<< "phones: " ; // print name
    for( const phone& ph : per.phone_numbers ) // for each phone, print phone number
        std::cout << ph.number << ' ' ;
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/5e80ef2a37ec412f
I may be a hobbyist programmer, not a professional, but I've been learning (badly) C++ since before the C++98 standard. Back when it was known as ANSI C++.

And Windows 95 was a hot topic for GUI programming.

I have PPPC++2E as part of my library. It is targeted for beginners, but at a higher level than a script kiddie.
Thank you Gentlemen all.

JLBorges, you really made the point clearly and simply. Thanks for the example. That was far more work than I expected. Somewhere I had seen someone referring to inheritance designs as "Coding C# or Java in C++" which was how I saw my approach as being and didn't want to go down the wrong road. I've always preferred the composite class approach.

Furry Guy.. I've tested my install on Learn CPP and I'm starting that too. Thanks.

Niccolo.. Thanks. Can't say as I really followed all of the logic but I think I got the jist. I'm not at a stage yet were I would consider a shared pointer and even if I did, I'm not at a stage yet were I'm doing anything beyond a single user thread, that's assuming I can keep the & and * straight. This is not a professional effort by any means. As for sorting, the only reason I'm going with vector at all is for the random access and the fact that I'm working with collections of probably less than 10 items per vector. Performance is a very small concern but if I wanted sorting I would have gone with a Set instead.

Topic archived. No new replies allowed.