0

Question: How can I return a non-const ref from a static class function, and why is the code below not doing so?

I am trying to initialize vectors with a custom allocator that itself is initialized with a reference to a custom memory management class. Here's what that looks like:

Custom std::vector allocator initialized with reference to custom memory management class

template <class T, std::size_t N, std::size_t MAX_SIZE, int ID>
class short_alloc
{
  arena<N, MAX_SIZE, ID>& a_;    //this is the custom memory  mgmt class
... 
public:
  short_alloc(arena<N, MAX_SIZE, ID>& a) noexcept : a_(a) { 
  std::cout<< "copying from reference" << std::endl;
  }

However, I wish to have only 1 memory manager per template type, so I am trying to initialize the allocator with a singleton's GetInstance() method so that only 1 memory manager is created per template type:

Singleton class to ensure only 1 memory manager for each set of template parameters

template <typename T>
class Singleton
{
 public:
    static T* m_instance;
    static T& GetInstance(){
    if(!m_instance){
      m_instance = new T();
    }
    return m_instance;  
  };
};

Use case:

I instantiate vectors with the custom allocator/memory manager class like so:

template <class T, std::size_t N, std::size_t MAX_SIZE, int ID>
class SmallVector {
   public:
      std::vector<T, short_alloc<T, N, MAX_SIZE, 1>> vec;
      SmallVector() : vec(Singleton<arena<N, MAX_SIZE, ID>>::GetInstance()){ 
      std::cout << "running constructor" << std::endl;
      }
   ...
  }

and invoked in int main() like so:

SmallVector<int, MAX_BLOCK, MAX_INDIV, 1> s;

However, this yields a compiler error:

error: invalid initialization of non-const reference of type 'arena<3200ul, 400ul, 1>& from an rvalue of type 'arena<3200ul, 400ul, 1>*' return &m_instance;

So it seems as though my Singleton class is returning a const reference/r-type reference. How can I instead return an l-type reference?

Community
  • 1
  • 1
sunny
  • 3,853
  • 5
  • 32
  • 62
  • 3
    A pointer is not a reference. Try `return *m_instance;`. – Fred Larson Aug 03 '15 at 16:39
  • 2
    Your singleton is broken (not thread safe, leaks memory) and overly complex (hence these issues). Better would be to have a function template returning a reference to a local `static` instance. – Konrad Rudolph Aug 03 '15 at 16:42
  • @KonradRudolph I have not posted my full code as that is not pertinent to solving this problem (the destructor is not relevant here, right?). Also why is single-threaded code automatically defective? – sunny Aug 03 '15 at 16:50
  • You're supposed to post a minimal testcase, of which this is not one. There is far too much code here for a basic "didn't return a value of the correct type" error. – Lightness Races in Orbit Aug 03 '15 at 16:52
  • The fix for making that code thread safe does not only make it thread safe, it also makes it a lot more readable. See the current answer. – bku_drytt Aug 03 '15 at 16:52
  • The thread-safety fix has the caveat of opening the door to order-of-destruction issues. IMHO the best option is (1) not to use Singleton at all, and (2) if you cannot help it, instantiate all Singletons explicitly at startup before multiple threads are created. – Christian Hackl Aug 03 '15 at 16:56
  • @sunny Can you absolutely, certainly, 100% guarantee that your code will never, ever use multithreading, and that the singleton will be shared across? Then your code has no bug. But of course you cannot make such a guarantee (or rather, making it is a highly nontrivial design process, which *will* sometimes go wrong, and it simply doesn’t pay to make this guarantee). Single-threaded code is a-ok for many situations, but doing static initialisation in a non thread-safe way is just begging for trouble. – Konrad Rudolph Aug 03 '15 at 17:05

1 Answers1

4

The return type is Singleton&. However, in the return statement, you are using

return m_instance;  

That should be

return *m_instance;  

You can simplify your class by using:

template <typename T>
class Singleton
{
 public:
   static T& GetInstance(){

      // By using a static variable, its initialization is 
      // thread-safe, per C++11. That's another reason to
      // prefer this method.
      static T m_instance;

      return m_instance;  
   }
};
R Sahu
  • 204,454
  • 14
  • 159
  • 270