(containers)= # C++ Container classes In ROOT and C++, there are three general categories of containers you have to know about. ## Arrays Do a web search on "C++ arrays" to learn about these containers.[^f130] Briefly, to create a double-precision array of eight elements, you could say: Double_t myArray[8]; To refer to the 3rd element in the array, you might use (remember, in C++ the first element has an index of 0): Int_t i = 2; myArray[i] = 0.05; If you're new to C++, it won't be obvious that while **`myArray[2]`** is a `Double_t` object, the type of the name **`myArray`** (without any index) is `Double_t*`, or a {ref}`pointer ` to a `Double_t`. Getting confused? Let's keep it simple. If you've created arrays with values and errors... Double_t xValue[22]; Double_t xError[22]; Double_t yValue[22]; Double_t yError[22]; ...and you've put numbers into those arrays, then you can create a `TGraphErrors` with: TGraphErrors* myPlot = new TGraphErrors(22,xValue,yValue,xError,yError); :::{note} Did you notice a problem with that example? I had to supply a fixed value for the number of points in each array to make the plot. In general, you won't be able to do that; in fact, in subsequent exercises you *can't* do that. In C++, one way to get around this problem is to use "dynamic arrays." I'll let you read about those on the web (search on "C++ dynamic arrays"), but I'm not going to say more about them, because I rarely use them. ::: ## ROOT's containers ROOT's container classes are described in chapter 16 of the [ROOT Users Guide](https://root.cern/root/htmldoc/guides/users-guide/ROOTUsersGuide.html). :::{note} In the `TGraphErrrors` constructors, the `TVectorF` and `TVectorD` classes are containers for single- and double-precision real numbers respectively. Click on the class names in the ROOT web site to see the clear and detailed explanation of how to use them.[^f131] I'll be blunt here, and perhaps editorialize too much: I don't like ROOT's collection classes. The main reason is that most of them can only hold pointers to classes that inherit from `TObject`. For example, if you wanted to create a `TList` that held strings or double-precision numbers (`TString` and `Double_t` in ROOT), you can't do it.[^f132] You need to know a little about ROOT's collection classes to be able to understand how ROOT works with collections of objects. For any other work, I'm going to suggest something else: ::: ## C++ Standard Template Library (STL) Do a web search on "standard template library". Skim a few sites, especially those that contain the words "introduction" or "tutorial". You don't have to get too in-depth; for example, you probably don't have enough time today to fully understand the concept of iterators. :::{note} Did you guess that STL is my preferred method of using containers in C++? The Standard Template Library is an important development in the C++ programming language. It ties into the concepts of design patterns and generic programming, and you can spend a lifetime learning about them.[^f133] ::: ## Vectors :::{note} For the work that you'll be asked to do in the {ref}`advanced exercises`, {ref}`expert exercises`, and probably for the rest of this summer, there's only one STL class you'll have to understand: vectors. Here are the basics. ::: If you want to use vectors in a program, or even a ROOT macro, you have to put the following near the top of your C++ code: #include To create a vector that will contain a certain type, e.g., double-precision values: std::vector myVector; If you want to create a vector with a fixed number of elements, e.g., 8: std::vector myOtherVector(8); To refer to a specific element of a vector, use the same notation that you use for C++ arrays: myOtherVector[2] = 0.05; To append a value to the end of the vector, which will make the vector one element longer, use the push_back() method: myVector.push_back( 0.015 ); To find out the current length of a vector, use the size() method: Int_t length = myVector.size(); Here's a simple code fragment that loops over the elements of a vector and prints them out. :::{code-block} c++ for ( size_t i = 0; i != someVector.size(); ++i ) { std::cout << "The value of element " << i << " is " << someVector[i] << std::endl; } ::: You have a vector, but TGraphErrors wants a C++ array name. Here's the trick: :::{code-block} c++ // Define four vectors. std::vector x,y,ex,ey; // Put values in the vectors (omitted so you can do it!) Int_t n = x.size(); TGraphErrors* plot = new TGraphErrors(n, x.data(), y.data(), ex.data(), ey.data()); ::: In other words, if `v` has the type `std::vector,` then `v.data()` is equivalent to the underlying `Double_t` array. We're getting closer to being able to tackle the {ref}`first advanced exercise `! [^f130]: If you're doing these exercises in Python: You'll want to read up on numpy arrays instead. Fortunately, numpy arrays will automatically be converted to C++ arrays when they're passed as arguments to ROOT methods. [^f131]: If you did this and are puzzled by my description, search the web for the definition of "sarcasm." [^f132]: In previous versions of this tutorial, I spent a couple of pages discussing object inheritance, and what it means to, e.g., "inherit from `TObject`." The new ROOT web documentation makes it harder to determine object inheritance; you often have to actually look at ROOT's C++ source code. I decided to spare you that as much as possible. [^f133]: I've lost track of the number of your lifetimes I've spent. You're probably tired of the joke anyway.