This may be a very simple answer, I am not sure. I have to give the address of a variable to read in some values in root. I need different variable names because I want to compare them later. Is there a way to all in one step read them into correctly named variables (typed double) that are incrementally named (Detector_P0, Detector_P1, etc.). This is what I have so far: (I have it working for the branchName, but not the &variableName in SetBranchAddress()). Any advice would be greatly appreciated!!!
for (int i = 0; i < nb_det; i++) {
std::string branchVarName = "Detector_P" + std::string(to_string(i));
const char * branchVarNameC;
branchVarNameC = branchVarName.c_str();
All->SetBranchAddress(branchVarNameC,&???);
}
Your best option is to use an array or array like object, such as std::vector or std::array.
If the size of the array is known compile time, prefer to use std::array<double, SIZE>.
If the size of the array is known only at run time, use std::vector<double>.
Example using std::vector:
std::vector<double> data(nb_det);
for (int i = 0; i < nb_det; i++)
{
std::string branchVarName = "Detector_P" + std::string(to_string(i));
const char * branchVarNameC = branchVarName.c_str();
All->SetBranchAddress(branchVarNameC, &(data[i]));
}
Yes, with each Detector_P$ variable there are approximately like 5000 numbers associated with each. When I run this file I do know right away how many there Detector_P variables there will need to be. So I would like to somehow create an array for each or at the very list something I can increment over to compare certain indices
It seems like you need a std::map<std::string, std::vector<double>> to hold the data.
std::map<std::string, std::vector<double>> allDetectorData;
for (int i = 0; i < nb_det; i++)
{
std::string branchVarName = "Detector_P" + std::string(to_string(i));
const char * branchVarNameC = branchVarName.c_str();
All->SetBranchAddress(branchVarNameC, allDetectorData[branchVarName]);
}
That allows you to read as many or as few doubles corresponding to a detector and store them in allDetectorData[branchVarName].
However, what concerns me most is how much of this makes sense to you. It will be worth your while to spend time understanding the container class templates in the standard library really well before venturing into using them in your application. I recommend learning about them from a good textbook.
Related
I am new to c++ in general. So I have been trying to learn about using vectors after someone recently helped with using an Arduino type project to read RFID tags. It really got me thinking I have no clue how to program. So I hit the books!
So here is the question: When I do the following code:
#include <iostream>
#include <vector>
struct Runner{
char runnerTag[32];
uint32_t ts;
};
std::vector<Runner > runners;
int main() {
std::cout << "Hello, Runners!\n";
for (int i = 0; i < 100; i++) {
std::string runnertg = "testTrackTag01";
uint32_t timeStamp = rand() % 100 + 1;
runners[i] = new Runner({runnertg, timeStamp});
}
return 0;
}
I get this annoying little message from xcode:
No matching constructor for initialization of 'Runner'
on line 16 of the above snippet. What in the world am I doing wrong?
The expression new Runner({runnertg, timeStamp}) has a type mismatch. runnertg is of type std::string, while the element Runner::runnerTag is of type char[32].
The expression runners[i] = new Runner({runnertg, timeStamp}); has another type mismatch. The element type of runners is Runner, while the expression new Runner({runnertg, timeStamp}) is of type Runner*.
runners[i] is out-of-bound access. The size of runners is 0. The elements runners[i] for all values of i does not exist.
There is memory leak since there is no matching delete for each new for all code path.
Don't use rand().
A lot of the code you're using is old style C with some C++ STL code mixed in. I will try and tackle a few issues one at at time.
struct is an abstract data type used (in general) to organise primitive data types. While the only difference between a struct and a class is that the latter defaults all members to private and in this case is not functional, it's a good to cut these things of at the pass.
Secondly, an array of chars is cumbersome, messy and prone to error. Try an std::string instead.
Finally, let's create a constructor taking our two parameters.
Thus:
#include <string>
class Runner {
public:
std::string runnerTag;
uint32_t ts;
Runner(std::string, uint32_t);
};
Next thing. Using an array index operator [] to access or modify an std::vector is dangerous and defeats the purpose of using a container and all the wonderful functionality that comes along with it.
Since you know for loops, let's try this:
for (int i = 0; i < 100; i++) {
std::string runnertg = "testTrackTag01";
uint32_t timeStamp = rand() % 100 + 1;
Runner Runner(runnertg, timeStamp);
runners.push_back(Runner);
}
At the end of your code, outside the scope of the main function, define the constructor as follows:
Runner::Runner(std::string rt, uint32_t ts) {
runnerTag = rt;
ts = ts;
}
This should get you started.
You cannot convert std::string to a char array like that. Change the type of the member variable runnerTag to std::string. Also, you are accessing vector elements that don't exist. Use resize to create them. Or better yet, use emplace_back to do both at once. Also, don't use int to iterate containers, but std::size_t. Also, don't use rand(), but the classes from the <random> header. That trick using % creates a non-uniform distribution.
I have long used pointers to arrays in C programs of the form:
int (*myarray)[2] = (int (*)[2]) malloc(n*sizeof(int[2]));
However, how can I do this in C++ using new? Can I do this?
int (*myarray)[2] = (int (*)[2]) new int[n][2];
EDIT:
Looks like my original post was incomplete and confusing. Here is a code snippet that I compiled and tested which appears to do the right thing but I wanted to confirm from C++ experts that I was using an appropriate C++ construct.
#include <iostream>
int main() {
int n=5;
int (*A)[2] = new int[n][2];
for (int i = 0; i < n; i++)
for (int j = 0; j < 2; j++)
A[i][j] = 2*i+j;
for (int i = 0; i < n; i++)
std::cout << A[i][0] << " " << A[i][1] << "\n";
delete myarray;
}
The joys of using C++ and STL is you get a vector class that provides array like behaviour.
This also makes it easier to manage and read...
std::vector< std::vector<int> > myarray(n);
If you don't want to use the STL then there is always...
typedef int intarray[2];
intarray* ints = new intarray[n];
ints[0][0] = 1;
...
ints[n-1][1] = 6;
I personally would write an extra line of code if it made the code easier to read.
I think the clearest way to do what you ask for is to use a typedef for the array:
typedef int array_t[2];
array_t* yourarray = new array_t[n];
Don't do that though, because it requires doing manual memory management and that tends to be tedious, error-prone and brittle, in particular with respect to exception safety. Instead, take a look at the std::array class template (new in C++11, but otherwise available via Boost) and at the std::vector class template.
To clarify the different between storing std::vector and std::array in a container, the latter is typically more efficient when there is a small and fixed number of elements involved. The reason is that the array class doesn't allocate things dynamically as the vector does. For that, vector needs three pointers (beginning, end of used storage and end of allocated storage) plus of course the storage for the data itself (plus maybe some overhead induced by the allocator) all of which need to be loaded into the CPU cache for use. Considering an LP64 system, that would require 32 bytes to store 8 bytes of data, compared to just 8 bytes using std::array.
Inside a function, I make a 2d array that fills itself from a text file and needs to get returned to main. The array stays a constant size through the whole program.
I know this is something that gets asked a lot, but I always seem to get one of two answers:
Use std::vector or std::array or some other STD function. I don't really understand how these work, is there any site actually explaining them and how they act compared to normal arrays? Are there any special #includes that I need?
Or
Use a pointer to the array, and return the pointer. First, on some of the answers to this it apparently doesn't work because of local arrays. How do I tell when it does and doesn't work? How do I use this array back in the main function?
I'm having more trouble with the concept of pointers and std::things than with the actual code, so if there's a website you know explains it particularly well, feel free to just put that.
Not necessarily the best solution, but the easiest way to get it working with vectors. The advantages are that you don't need to delete memory (happens automatically) and the array is bounds-checked in debug mode on most compilers.
#include <vector>
#include <iostream>
using array2D = std::vector< std::vector< int > >;
array2D MyFunc(int x_size, int y_size)
{
array2D array(y_size, vector< int >(x_size));
int i = 0;
for (int y = 0; y < array.size(); y++)
{
for (int x = 0; x < array[y].size(); x++)
{
// note the order of the index
array[y][x] = i++;
}
}
return array;
}
int main()
{
array2D bob = MyFunc(10, 5);
for (int y = 0; y < bob.size(); y++)
{
for (int x = 0; x < bob[y].size(); x++)
{
cout << bob[y][x] << "\n";
}
}
}
Live example:
http://ideone.com/K4ilfX
Sounds like you are new to C++. If this is indeed the case, I would suggest using arrays for now because you probably won't be using any of the stuff that STL containers give you. Now, let's talk about pointers.
You are correct that if you declare a local array in your function, the main function won't have access to it. However, this is not the case if you dynamically allocate the array using the new keyword. When you use new to allocate your array, you essentially tell the compiler to reserve a chunk of memory for your program. You can then access it using a pointer, which is really just the address of that chunk of memory you reserved. Therefore, instead of passing the entire array to the main function, all you need to do is pass a pointer (address) to that array.
Here are some relevant explanations. I will add to them as I find more:
Dynamic Memory
The easiest way to create a 2d array is as follows:
char (*array)[10];
array = new array[5][10];
Two dimensional arrays can be tricky to declare. The parenthesis above in the variable declaration are important to tell the compiler array is a pointer to an array of 10 characters.
It is really essential to understand pointers with C and C++ unless using the std:: collections. Even then, pointers are widely prevalent, and incorrect use can be devastating to a program.
I have a for-loop that needs to incrementally add columns to a matrix. The size of the rows is known before entering the for-loop, but the size of the columns varies depending on some condition. Following code illustrates the situation:
N = getFeatureVectorSize();
float **fmat; // N rows, dynamic number of cols
for(size_t i = 0; i < getNoObjects(); i++)
{
if(Object[i] == TARGET_OBJECT)
{
float *fv = new float[N];
getObjectFeatureVector(fv);
// How to add fv to fmat?
}
}
Edit 1 This is how I temporary solved my problem:
N = getFeatureVectorSize();
float *fv = new float[N];
float *fmat = NULL;
int col_counter = 0;
for(size_t i = 0; i < getNoObjects(); i++)
{
if(Object[i] == TARGET_OBJECT)
{
getObjectFeatureVector(fv);
fmat = (float *) realloc(fmat, (col_counter+1)*N*sizeof(float));
for(int r=0; r<N; r++) fmat[col_counter*N+r] = fv[r];
col_counter++;
}
}
delete [] fv;
free(fmat);
However, I'm still looking for a way to incrementally allocate memory of a two-dimensional array in C/C++.
To answer your original question
// How to add fv to fmat?
When you use float **fmat you are declaring a pointer to [an array of] pointers. Therefore you have to allocate (and free!) that array before you can use it. Think of it as the row pointer holder:
float **fmat = new float*[N];
Then in your loop you simply do
fmat[i] = fv;
However I suggest you look at the std::vector approach since it won't be significantly slower and will spare you from all those new and delete.
better - use boost::MultiArray as in the top answer here :
How do I best handle dynamic multi-dimensional arrays in C/C++?
trying to dynamically allocate your own matrix type is pain you do not need.
Alternatively - as a low-tech, quick and dirty solution, use a vector of vectors, like this :
C++ vector of vectors
If you want to do this without fancy data structures, you should declare fmat as an array of size N of pointers. For each column, you'll probably have to just guess at a reasonable size to start with. Dynamically allocate an array of that size of floats, and set the appropriate element of fmat to point at that array. If you run out of space (as in, there are more floats to be added to that column), try allocating a new array of twice the previous size. Change the appropriate element of fmat to point to the new array and deallocate the old one.
This technique is a bit ugly and can cause many allocations/deallocations if your predictions aren't good, but I've used it before. If you need dynamic array expansion without using someone else's data structures, this is about as good as you can get.
To elaborate the std::vector approach, this is how it would look like:
// initialize
N = getFeatureVectorSize();
vector<vector<float>> fmat(N);
Now the loop looks the same, you access the rows by saying fmat[i], however there is no pointer to a float. You simply call fmat[i].resize(row_len) to set the size and then assign to it using fmat[i][z] = 1.23.
In your solution I suggest you make getObjectFeatureVector return a vector<float>, so you can just say fmat[i] = getObjectFeatureVector();. Thanks to the C++11 move constructors this will be just as fast as assigning the pointers. Also this solution will solve the problem of getObjectFeatureVector not knowing the size of the array.
Edit: As I understand you don't know the number of columns. No problem:
deque<vector<float>> fmat();
Given this function:
std::vector<float> getObjectFeatureVector();
This is how you add another column:
fmat.push_back(getObjectFeatureVector());
The number of columns is fmat.size() and the number of rows in a column is fmat[i].size().
I need to create a large two dimensional array of objects. I've read some related questions on this site and others regarding multi_array, matrix, vector, etc, but haven't been able to put it together. If you recommend using one of those, please go ahead and translate the code below.
Some considerations:
The array is somewhat large (1300 x 1372).
I might be working with more than one of these at a time.
I'll have to pass it to a function at some point.
Speed is a large factor.
The two approaches that I thought of were:
Pixel pixelArray[1300][1372];
for(int i=0; i<1300; i++) {
for(int j=0; j<1372; j++) {
pixelArray[i][j].setOn(true);
...
}
}
and
Pixel* pixelArray[1300][1372];
for(int i=0; i<1300; i++) {
for(int j=0; j<1372; j++) {
pixelArray[i][j] = new Pixel();
pixelArray[i][j]->setOn(true);
...
}
}
What's the right approach/syntax here?
Edit:
Several answers have assumed Pixel is small - I left out details about Pixel for convenience, but it's not small/trivial. It has ~20 data members and ~16 member functions.
Your first approach allocates everything on stack, which is otherwise fine, but leads to stack overflow when you try to allocate too much stack. The limit is usually around 8 megabytes on modern OSes, so that allocating arrays of 1300 * 1372 elements on stack is not an option.
Your second approach allocates 1300 * 1372 elements on heap, which is a tremendous load for the allocator, which holds multiple linked lists to chunks of allocted and free memory. Also a bad idea, especially since Pixel seems to be rather small.
What I would do is this:
Pixel* pixelArray = new Pixel[1300 * 1372];
for(int i=0; i<1300; i++) {
for(int j=0; j<1372; j++) {
pixelArray[i * 1372 + j].setOn(true);
...
}
}
This way you allocate one large chunk of memory on heap. Stack is happy and so is the heap allocator.
If you want to pass it to a function, I'd vote against using simple arrays. Consider:
void doWork(Pixel array[][]);
This does not contain any size information. You could pass the size info via separate arguments, but I'd rather use something like std::vector<Pixel>. Of course, this requires that you define an addressing convention (row-major or column-major).
An alternative is std::vector<std::vector<Pixel> >, where each level of vectors is one array dimension. Advantage: The double subscript like in pixelArray[x][y] works, but the creation of such a structure is tedious, copying is more expensive because it happens per contained vector instance instead of with a simple memcpy, and the vectors contained in the top-level vector must not necessarily have the same size.
These are basically your options using the Standard Library. The right solution would be something like std::vector with two dimensions. Numerical libraries and image manipulation libraries come to mind, but matrix and image classes are most likely limited to primitive data types in their elements.
EDIT: Forgot to make it clear that everything above is only arguments. In the end, your personal taste and the context will have to be taken into account. If you're on your own in the project, vector plus defined and documented addressing convention should be good enough. But if you're in a team, and it's likely that someone will disregard the documented convention, the cascaded vector-in-vector structure is probably better because the tedious parts can be implemented by helper functions.
I'm not sure how complicated your Pixel data type is, but maybe something like this will work for you?:
std::fill(array, array+100, 42); // sets every value in the array to 42
Reference:
Initialization of a normal array with one default value
Check out Boost's Generic Image Library.
gray8_image_t pixelArray;
pixelArray.recreate(1300,1372);
for(gray8_image_t::iterator pIt = pixelArray.begin(); pIt != pixelArray.end(); pIt++) {
*pIt = 1;
}
My personal peference would be to use std::vector
typedef std::vector<Pixel> PixelRow;
typedef std::vector<PixelRow> PixelMatrix;
PixelMatrix pixelArray(1300, PixelRow(1372, Pixel(true)));
// ^^^^ ^^^^ ^^^^^^^^^^^
// Size 1 Size 2 default Value
While I wouldn't necessarily make this a struct, this demonstrates how I would approach storing and accessing the data. If Pixel is rather large, you may want to use a std::deque instead.
struct Pixel2D {
Pixel2D (size_t rsz_, size_t csz_) : data(rsz_*csz_), rsz(rsz_), csz(csz_) {
for (size_t r = 0; r < rsz; r++)
for (size_t c = 0; c < csz; c++)
at(r, c).setOn(true);
}
Pixel &at(size_t row, size_t col) {return data.at(row*csz+col);}
std::vector<Pixel> data;
size_t rsz;
size_t csz;
};