2

I am writing a plugin for the CFD software OpenFOAM in C++. My code will read information from each cell in the model (>100k cells) for each time step of the analysis. I have a list of lists of doubles called C that is initialized with zeros in the first time step and is changing in the next time steps, however the size stays the same.

My problem is that the initialization of the list in the first time step takes too much time. In the following time steps I can easily loop over all elements in the list and perform some computations on those values and store them again. In the first time step however I have an empty list of size 0 which means that I have too append zeros to initialize it. I do know the final size of the list so I could easily write

Foam::List<Foam::List<double>> C (size,0.0);

in the first time step and my problem would be solved (this is the OpenFOAM specific list class https://www.openfoam.com/documentation/guides/latest/api/classFoam_1_1List.html)

However, if I want to define my list of lists once and then use it through out all the time steps I need to define it in the header file. In the header file I don't know the size though, which means that I define it as

Foam::List<Foam::List<double>> C;

in the header file and then fill it with zeros in the C file. And this is my problem - how do I initialize an already defined list of lists with zeros in the C file?

If this would've been C# I could've split it into two rows as

List<List<double>> C;
C = new List<List<double>>(size);

and write the first line in the header file and the second line in the C file (as far as I understand it). How can I do something similar in C++?

Very thankful for help on this.

Thanks, David

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
  • What is `List` here? are you referring to `std::list`? – Max Jan 08 '20 at 09:27
  • If you are using `std::list` you should probably switch to `std::vector` – Alan Birtles Jan 08 '20 at 09:28
  • Surely you want a `std::vector` (which is contiguous memory) rather than a `list` (which is a linked list, with all the overheads that implies? Also if you just want a 2D array of numbers, you can allocate a vector of width*height and do the indexing yourself. You don't need the data structure to be 2D. – gavinb Jan 08 '20 at 09:28
  • I am actually writing directly in the software which is using C++ but with it's own layer lets say, so it's rather Foam::List<...>. But for sake of clarity I will change it to std::list for now – David Andersson Jan 08 '20 at 09:30
  • Please link the documentation of `Foam::List`. We would need to know which constructors that class offers. Don't just switch to `std::list` it's a very specific and rarely used container. Better make clear, what `Foam::List` is. – Max Jan 08 '20 at 09:31
  • It is unclear whether `C` is a global variable declared/defined in the header or whether it is a class member of a class defined in the header. How you initialize it correctly depends on that. Can you provide a minimal version of the header file that shows exactly what you're trying to do? It's similarly not clear when you actually know the size you need. "In the C file" could mean "at static initialization time", "when some `init` function is called", "on class construction" etc. – Max Langhof Jan 08 '20 at 09:54
  • Do you need the OpenFOAM stuff? `std::vector` sounds like a much better pick, maybe even one array for the entire list of lists (make it `width * height`, then use `[x + y * width]` to access). – Fire Lancer Jan 08 '20 at 09:57
  • @MaxLanghof the header file looks something like this: `class myPlugIn: { protected: Foam::List> C; ..}; ` – David Andersson Jan 08 '20 at 10:09
  • @DavidAndersson Ok, that's an important detail that should be part of the question. Right now it looks like you're trying to initialize a global variable. – Max Langhof Jan 08 '20 at 10:22

3 Answers3

2

Assuming Foam::List<Foam::List<double>> C; is defined in your .h-file and size is a two element array holding the the two sizes of your list, you should be able to do:

C=Foam::List<Foam::list<double>>(size[0],Foam::List<double>(size[1],0));

Another thing, that I think you should know, is that the keyword new should not be used in c++ for things like this. The keyword new allocates memory on the heap instead of the stack. Whenever you use new you will also have to use delete later on to avoid memory leaks. Usually this is done by using new in a classes CTOR and delete in the classes DTOR. As correctly pointed out by @MaxLanghof in modern C++ you should always prefer the use of smart pointers like std::shared_pointer, std::unique_pointer and std::weak_pointer over the use of new and delete

Max
  • 1,471
  • 15
  • 37
  • This works perfectly! I tried `C=Foam::List>(size,0.0);` before but it didn't work and I now understand why, pretty obvious actually. Thanks @Max ! – David Andersson Jan 08 '20 at 10:17
  • @DavidAndersson No worries. See my edit, for another thing, that I would like to draw your attention to. – Max Jan 08 '20 at 10:22
  • Re `new`: While you are technically correct, this is generally not done at all (manually) in modern C++. You refrain from using naked `new`/`delete` and use e.g. smart pointers (`std::unique_ptr` etc.) instead. – Max Langhof Jan 08 '20 at 10:23
1

Since the variable you want to initialize is the member of a class, the normal way to initialize it is to use the constructor's member initializer list:

Header file:

class MyPlugIn
{
public:
  MyPlugIn(int listSize); // constructor
protected:
  Foam::List<Foam::List<double>> C;
};

Source file:

MyPlugIn(int listSize) : C(listSize)
{
}

This of course requires the necessary size to be known at the time when MyPlugIn is created. If that is not the case, using the copy/move assignment operator as shown in Max' answer is also a solution.

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
0

If it is a plain list, you can use any of these, depending on if you need to redimension or if it already has the correct size:

mylist.resize(size, Zero);
mylist = Zero;

If you have a list of lists, we'll assume that they have the correct sizes and just zero them:

for (auto &lst : mylistlist)
{
    lst = Zero;
}

I'd use the Zero constant rather than 0.0 or whatever - it makes the meaning clear and applies nicely to vector/tensor and other vector-space quantities if you need that in the future.

Mark.O
  • 94
  • 6