Question on pointers (ROOT TTree example)

In summary: In the first function, the pointer myPointer will be null because myFunction2 does not return a pointer to an int. In the second function, myPointer will be the pointer returned by myFunction2.
  • #1
ChrisVer
Gold Member
3,378
464
C:
TTree* inputTree = (TTree*)source->Get( "<YourTreeName>" );

Could someone please explain me what the above statements mean? I don't understand what " (TTree*) " does (source is a TFile). Thanks.
 
Technology news on Phys.org
  • #2
It seems to me that TTree is a class name. The part "TTree* inputTree" creates a pointer to a TTree object. Then this pointer is assigned to point to a TTree object whose pointer is given by "Get" method of the object "source" which means source is an object from a class that has a TTree member variable(probably as a pointer).
For more information, its better to take a look at the definition of the classes.
 
  • #3
The TTree structure is a block of memory that contains all of the information for the TTree. a TTree * tells you the memory location of the struct.

Is this C or C++? I'm assuming C based on the tag and the C cast.
 
  • #4
I don't think that the definition of these classes could help.
I had problem understanding the meaning of (TTree*) and not what TTree is used for/how and what methods it has.
 
  • #5
and it's C++ I guess (since ROOT is using C++). But I think it's a general concept that may appear when you deal with pointers to write something like:

int * p = (int*)a->(method in int)
 
Last edited:
  • #6
Okay, forget the TTree and go to int, ints are easy.

You know that your int is stored in memory right? Memory is laid out in a massive block (actually two of them, stack and heap) and everything gets stored there. Okay, so you make an int.

Code:
int one = 1;  //int on the stack, value of 1

Now you have an int, and any time you use it, you will get the value 1. How does the computer know that? Because it's stored a 32 representation of that bit in memory somewhere, your compiled program knows exactly where that memory is, it couldn't care less what you call your variable. To you, your variable is called "one" to the computer, your variable is called "top of stack + offset" where those are memory locations. If you want to know that memory address yourself, you take it's pointer. That will create a separate variable, whose value will be the value of "top of stack + offset"

Code:
int * oneptr = &one;//pointer on the stack, value of the location of "one"

I recommend looking elsewhere for examples, where ever you got your code from is fairly poor. You have a cast form one type of pointer to another after the method call, good code will just return the correct type. You also have a C cast in C++ code. Probably an easier way to learn about pointers is to learn how strings work in C.
 
  • #7
C and C++ are strongly typed languages.
What that means is each and every variable must have a type (int, float, char etc), and conversion between types has to follow strict rules.

What you have in your code is you are creating a variable in the local scope that is a pointer to TTree named input tree
Code:
TTree* inputTree   //create a variable named inputTree of type TTree pointer

You are assigning to this variable the returned value from the call to source->Get.
It is likely that source->get returns a TTree* already. However it is always good coding practice to explicitally cast returned pointers to what type it is.
That is done with the (TTree*).

Hope that make sense!
 
  • #8
cpscdave said:
However it is always good coding practice to explicitally cast returned pointers to what type it is.
That is done with the (TTree*).

Hope that make sense!
This is extremely incorrect. It is good coding practice to do exactly the opposite and use the -Wall option in the compiler to make sure it's what you expect, these languages are very strongly typed on purpose. Other languages let you go back and forth between types willy-nilly because the concept of a variable is abstract, in C/C++ they are coupled directly to the structure of memory.

Even if you do perform casting from time to time, in c++ you should never use that style cast, here is why:

Code:
int i = 10;  //32 bits
long j = 100L;  //64 bits
long * jp = (int *)jp;  //C cast, no checking, telling the compiler that you know better
*jp = 100L;  //Write 64 bit constant to 32 bit memory chunk.  Holy, memory corruption!

Properly written code
Code:
int i = 10;
long j = 100L;
long * jp = static_cast<int *>(jp);  //Proper style of cast, will not compile
*jp = 100L;
 
Last edited:
  • Like
Likes jim mcnamara
  • #9
newjerseyrunner said:
This is extremely incorrect.

First off you'll notice I said RETURNED pointers.
It has everything to do with readability of the code.

Imagine this situation:
int* myFunction() { //some stuff}

void myFunction2()
{
int* myPointer;
//a bunch of code
myPointer = (int*) myFunction()
}

you've done nothing to affect the operation of the code. You've cast an int* to an int*.
But 6 months later when you're reviewing the code for whatever reason you won't need to search through the code to figure out what myPointer is supposed to be.
 
  • #10
cpscdave said:
First off you'll notice I said RETURNED pointers.
It has everything to do with readability of the code.

Imagine this situation:you've done nothing to affect the operation of the code. You've cast an int* to an int*.
But 6 months later when you're reviewing the code for whatever reason you won't need to search through the code to figure out what myPointer is supposed to be.

Documentation should provide you with hints as to what things are supposed to be, your IDE will also usually both be able to tell you and return you back to the definition of your variable. Returned pointers are no different than any other ones, and the cast itself IS a function, so you do have a returned value. Programmers will not sacrifice code safety for readability.

Here is a difference maintenance nightmare for you. Your code now requires a 64 bit long to replace that 32 bit int. Change the function, but forget to change a single cast, and suddenly you have a very difficult to track down bug. If you had not done any casts, your compiler will tell you what you did wrong, if you used a proper C++ cast, it'll do the same, using a C cast will not hinder compilation, just produce weird behavior. When you start getting into inheritance you start getting ever worse issues.

There is no reason to EVER use a C cast in C++ code.

Code:
//Assume Child inherits publically from Parent and getObjectByName is implemented elsewhere

Parent * getObjectByName(const char * name);

Child * mychild = getObjectByName("child");  //Will not compile because the return type and assigned type are not the same INVALID!

Child * mychild = (Child*)getObjectByName("child");  //mychild is valid ONLY if it were created with the Child() constructor  UNSAFE!

Child * mychild = reinterpret_cast<Child *>(getObjectByName("child"));  //mychild is valid ONLY if it were created with the Child() constructor  UNSAFE!

Child * mychild = static_cast<Child*>(getObjectByName("child"));  //Will not compile because of reason above INVALID!

try {
     Child * mychild = dynamic_cast<Child *>(getObjectByName("child"));  //mychild is valid if it were created with the Child() constructor OR you've defined a conversion SAFE!
} catch (const std::bad_cast& e) { }
 
  • #11
cpscdave said:
However it is always good coding practice to explicitally cast returned pointers to what type it is.
I'm with @newjerseyrunner on this. This is very widely regarded as a poor programming practice. Many C++ projects make it a rule to compile with -Wold-style-cast compilation flag so that (TTree*)source->Get("<YourTreeName>") gets flagged with a warning (or with an error if you've enabled -Werror).

This forces one to use new style casts (e.g., reinterpret_cast<TTree*>(source->Get("<YourTreeName>")) instead of C-style casts. Those new style casts do not enhance readability. They are instead a big red flag that the programmer may be doing something underhanded. Which is a good thing. Those new-style casts are easy to find using something like grep.
 
  • #12
Is it a big problem that I find it difficult to follow the conversation from Post8 and on?
 
  • #13
Memory is divided up by 1 byte chunks. Each 1 byte chunk of memory has an address, which is just a number that refers to it. A pointer in C or C++ is just a variable for holding a memory address of one of these 1 byte chunks of memory. Types are associated with the pointer in C or C++, because variables may be represented with more than one byte and may need to be stored or parsed differently. An int is typically 4 bytes for example. If you have a pointer to an int, then the compiler knows that the value in memory is represented with the 4 consecutive bytes of memory, starting with the byte referred to by the pointer, and that it is an integer.

There is also the void pointer, which is just the address, without the type information. This is used, usually in C, to allow functions to be general enough to allow different types of variables to be passed or returned from the same function. For example, to pass a variable to a function as a void pointer and then use it, you first cast it to a void *, (void*), which would be necessary as this would be the type of the parameter of the function, then in the function, you would cast back to a pointer to the actual type, e.g. (Root *), before using it.

In C++, this technique is usually not used, because features exist to accomplish the same things, such as templates, and functors. But in C++ there is also polymorphism, which is one source of a need to typecast pointers from one type to another, and may be what's going on in the code you posted. If you are unfamiliar with Polymorphism in C++, then I suggest reading something on it.

C:
TTree* inputTree = (TTree*)source->Get( "<YourTreeName>" );

source is a pointer to an Object which has a function Get, that takes a string as input and returns a pointer to something. In this code snippet, whatever type of pointer it returns, is type casted to a pointer to the type Tree, before it is assigned to TTree, which is redundant because it's just a number that is assigned, and TTree* is the type of the variable, which cannot be changed, but requiring it makes it more clear what may be going on, and helps the compiler to warn you, or optionally generate errors for things that may be unsafe.
 
Last edited:
  • Like
Likes FactChecker
  • #14
ChrisVer said:
Is it a big problem that I find it difficult to follow the conversation from Post8 and on?
I apologize, that may be my fault. There was a minor issue with what you posted I wanted to clarify about typecasting, but as for your question @tAllan's explanation of pointers is very good. A pointer just points to a block of memory. In your case that block of memory represented a TTree.
 
  • #15
@ChrisVer --
What they are talking about above is undefined behavior, the nasty child of
C and C++ runtime possibilities, along with it's ugly cousin, unspecified behavior.

Undefined behavior for a program is just that: abort, corrupt data, do something
you could never expect: reformat your hard drive or send a picture of your
family to the Mars Lander. You may think that's funny. I worked for DOE in
Germantown MD long ago. We were debugging garbage code that had problems. We hit
a problem, and Voila! there we were sitting at the console prompt of another
machine. That was no joke. We panicked, shut everything down and reported it to
security. We thought we were safe on the local machine. Nope.

You may think the Mars Lander thing above is hyperbole, and it probably is, but it
makes the point.

Undefined behavior is the concept behind hacker code exploits to take over a
machine. What happened in the "long ago" example was to unintentionally
overwrite the return address on the stack, and then when the function ended,
return to some other wildly different place in computer memory. Instead of
staying in the current process memory. Undefined behavior.

So, if you are coding C or C++ you should be aware of this, especially if you
are downloading code from everywhere.

C++ has many more creative ways to demonstrate undefined behavior than does C.

Getting your head around the C++ issue set is a huge task, so for C here is
CERT on C secure programming:
https://www.securecoding.cert.org/confluence/display/c/SEI+CERT+C+Coding+Standard

Floating point examples:
(for purists who know about IEEE-754 2008 this page assumes you have commodity computers and are coding C)
https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=158237216

https://www.securecoding.cert.org/c...nt+numbers+when+precise+computation+is+needed

Why? You seem to work in Physics extensively. You can see examples of fp operations that give
incorrect results and how to fix them. Check out the last link for an example.
 
  • Like
Likes FactChecker and ChrisVer
  • #17
ChrisVer said:
Is it a big problem that I find it difficult to follow the conversation from Post8 and on?
Sorry Chris -- I don't often look in this forum. (Maybe I should check more often to see if there's C++ questions here.)

Your original code is obviously C++ (since it involves member function). C++ is strongly typed, C is not (though this can depend on one's precise definition of "strongly"). The expression (TTree*) is a cast operator, forcibly converting whatever the "Get(...)" mbr fn returns into a TTree*.

BTW, someone said that "always casting" in this way is good practice. Sorry, but that's rubbish. In C++, if you need to cast, then something is deficient about the overall class structure.
In this context, you said earlier:
I don't think that the definition of these classes could help.
...it could indeed help to know the type (class) of which "source" is an instance, hence what type is returned by "source->Get(...)" .

If your question is still not answered then try re-phrasing it. Have you got Bjarne Stroupstrup's definitive tome(s)?
 
Last edited:

Related to Question on pointers (ROOT TTree example)

What are pointers and how are they used in ROOT TTree?

Pointers are variables that store the memory address of another variable. In ROOT TTree, pointers are used to access and manipulate data stored in branches of a TTree. Pointers point to the first element of an array of data, allowing for efficient access and manipulation of large datasets.

How do I create and initialize a pointer in ROOT TTree?

To create and initialize a pointer in ROOT TTree, you can use the new keyword followed by the data type and the number of elements in the array. For example, int *myPointer = new int[100]; creates a pointer to an array of 100 integers.

How do I access data using pointers in ROOT TTree?

To access data using pointers in ROOT TTree, you can use the SetBranchAddress function. This function takes the name of the branch and the address of the pointer as arguments. For example, myTree->SetBranchAddress("branchName", &myPointer); will set the address of the pointer to the data in the specified branch.

How do I delete a pointer in ROOT TTree?

To delete a pointer in ROOT TTree, you can use the delete keyword followed by the name of the pointer. This will free up the memory used by the pointer and its associated data. It is important to properly delete pointers to avoid memory leaks in your code.

Can I use pointers to access nested branches in ROOT TTree?

Yes, you can use pointers to access nested branches in ROOT TTree. This can be done by using the dot notation to access the nested branch, followed by the SetBranchAddress function. For example, myTree->SetBranchAddress("branchName.nestedBranchName", &myPointer); will set the address of the pointer to the data in the nested branch.

Similar threads

  • Programming and Computer Science
Replies
7
Views
1K
  • Programming and Computer Science
Replies
7
Views
3K
  • Programming and Computer Science
Replies
12
Views
1K
  • Programming and Computer Science
2
Replies
40
Views
2K
  • Programming and Computer Science
Replies
17
Views
1K
  • Programming and Computer Science
Replies
19
Views
3K
  • Programming and Computer Science
Replies
17
Views
2K
  • Programming and Computer Science
Replies
0
Views
599
  • Programming and Computer Science
Replies
1
Views
705
  • Programming and Computer Science
Replies
6
Views
1K
Back
Top