简体   繁体   中英

Hiding variables in a namespace C++

I have a function which aims to perform a recursive calculation. If my function is programmed recursively, it takes too long to compute. Therefore, I perform memoization by storing intermediate results in an array.

During the execution of my program, I might call the function with parameters (10,0) , (5,5) , (2,4) etc. Therefore I have a setup(double x) function which fills the entire array with the correct values. I can then access any of the array values without any further calculations. I only wait until x changes to call setup() again.

I am wondering how I can go about implementing this in c++. It doesn't make sense to me to use a class, as I would never need to create the associated object. I have implemented the functions fine in a namespace, but I'm still having a problem. Even If I use an unnamed namespace, the array used by my function is visible and can be modified from outside the namespace of the function. If I include the header file of the namespace, that is.

my code:

FunctionWrapper.h

namespace FunctionWrapper{
      namespace{
            double tempArray[10][10];
      }

      void setup(double x);
      void getValues(int n);
}

Main.cpp

#include "FunctionWrapper.h"

int main(){
   FunctionWrapper::tempArray[0][0] = 5; //Works
}

If you do not want tempArray to be nameable in other source files, don't declare it in the header file. Instead, declare it in an unnamed namespace in FunctionWrapper.cpp . Then, it can only be used directly from within that source file.

In general, a header file should not use an unnamed namespace, as it can (and often will) cause One Definition Rule violations.

Note that a better solution to your problem might, in fact, be to create a class that provides this functionality:

class ValueGetter
{
public:
    ValueGetter(double x);
    void GetValues(int n);

private:
    double cache[10][10];
};

This way, you can create an instance of this type, and all of the state is owned by that instance. There are many benefits to avoiding global state, including increased maintainability and testability.

This does make sense as a class, and those functions as members of that class. Those functions act on that data, and you don't want anyone else to have access to that data, that sounds like a perfect use for a class. Why are you opposed to that?

Further to James's (as usual, excellent) answer, I'd structure things something like this:

namespace {
class value_cache { 
     double temp_array[10][10];
     int x;
     void setup(double x);
     void internal_getValues(int); // same as your current GetValues
public:
     void getValues(int n) { 
         if (x != n) 
            setup(x=n);            
         internal_getValues(n);
     }
};
}

double function(int x, int y) {
     static value_cache c;

     c.getValues(x); 
     // probably more stuff here.
}

I see three options here:

  1. Put the anonymous namespace in the .cpp file where your memoized function is implemented. It will then not be able to be access from anywhere else.
  2. Make the array containing the memoized results a static variable inside the class.
  3. Make a class that implements operator () , and use an instance of it as your 'function'. Then the memoization array can be a private member variable of that class.

Option 1 is the very simplist, and it will work. Of course, if your function is ever used in a multi-threaded environment you're going to have to think about inter-thread synchronization of access to the memoized value data structure.

Option 2 is a variant on option 1. Personally, I think it's the one you should go for. It has the exact same drawback though.

Option 3 is, IMHO, rather fiddly. In order to have something that looks and acts like your function you will have to declare a global variable of the class. But that's basically a singleton. And while that might be OK in this case, it may end up being a huge pain down the road.

There is one other option, but it's a huge amount of work. It's basically making a memoizing template. It would operate like option 3, but you could instantiate it for any function who's arguments satisfied the criteria for being keys of a hashmap.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM