0

Working on a large project concerning C++ and Matlab cooperation through Mex we are currently struggling with one of our singletons.

The class is being generated through macros during preprocessing so it may seem a bit odd.

class AdditionalOperation { 
private: 
    const std::string* val; 
    typedef std::map<std::string, const std::string*> StringMap; 

    static StringMap& getStringToPointerMap() 
    { 
        static StringMap map; 
        return map; 
    } 

    static boost::mutex& getMutex()
    { 
        static boost::mutex mutex; 
        return mutex; 
    } 

    AdditionalOperation(const std::string* s)
        :val(s) 
    {} 
private: 
    static std::string* none_string() 
    { 
        static std::string s = "none"; 
        static int count = 0; 
        boost::mutex::scoped_lock lock(getMutex()); 
        if(count++ == 0) { 
            getStringToPointerMap().insert(std::make_pair(s,&s)); 
        } 
        return &s; 
    } 
public: 
    static AdditionalOperation none() 
    { 
        return AdditionalOperation(none_string()); 
    } 

private: 
    static std::string* norm_string() 
    {   
        static std::string s = "norm"; 
        static int count = 0; 
        boost::mutex::scoped_lock lock(getMutex()); 
        if(count++ == 0) { 
            getStringToPointerMap().insert(std::make_pair(s,&s)); 
        } 
        return &s; 
    } 
public: 
    static AdditionalOperation norm() 
    { 
        return AdditionalOperation(norm_string()); 
    } 
private: 
    static void prepare() 
    { 
        none(); 
        norm(); 
    } 
public: 
    static AdditionalOperation fromString(std::string s) 
    { 
        static int count = 0; 
        if(count++ == 0) 
            prepare(); 
        boost::mutex::scoped_lock lock(getMutex()); 
        StringMap& map = getStringToPointerMap(); 
        StringMap::iterator location = map.find(s); 
        if(location == map.end()) { 
            throw UnknownEnumValue(s); 
        } 
        return AdditionalOperation(location->second); 
    } 

    std::string toString() const 
    { 
        return *val; 
    }

    bool operator==(const AdditionalOperation& other) const 
    { 
        return val == other.val; 
    } 

    bool operator!=(const AdditionalOperation& other) const 
    { 
        return !(*this == other); 
    } 
};

All this code is generated from this line (through macros as stated above):

DECLARE_SENUM(AdditionalOperation, none, norm);

Which is a nice interface that we'd like to keep on using.

We want to use this class as a replacement for enumerations because we need to translate them from string and to a string. In this class we have 2 'enumeration' members namely norm and none.

Now we have added some logging and have determined that the insert operation inside the none_string and norm_string function is being called twice even though our counter should prevent this.

Some things we have tried :

  • We are working with a dynamic library but using -rdynamic did not help.
  • When we print the address of the static variables we can clearly see that they differ.
  • This class is situated within a dynamic library which in turn is linked with a mex file. This mex file is being dynamically loaded by another mex file through dlopen.

We were thinking that perhaps multiple instances of this class are declared and active because of the dynamic library. But we also use other kind of singletons that have not shown any sign of problems.

I hope it was clear enough, additional information or clarification can always be provided!

Thanks in advance!

giriel
  • 93
  • 12
  • 1
    Why not simply add `operator<<(basic_ostream&, MyEnum)`? – Puppy Mar 04 '13 at 15:33
  • We are not interested in place our enumeration into an ostream. The string functionality is what we are after :) – giriel Mar 04 '13 at 15:41
  • @giriel: by defining a streaming operator, the conversion to string becomes near obvious. But anyway, you could have a `std::string to_string(MyEnum)` function and it would work as well. – Matthieu M. Mar 04 '13 at 16:10

1 Answers1

1

You are, clearly, overcomplicating the problem.

std::string const& to_string(MyEnum e) {
    static std::string const First = "First";
    static std::string const Second = "Second";

    switch(e) {
    case MyEnum::First: return First;
    case MyEnum::Second: return Second;
    }

    throw std::runtime_error("Unknown enum value");
}

would work as well, if not better and faster.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • We had something like that in our first solution but it is quite cumbersome to create such a method for all the enumeration you would possibly want. Next to that we also require a from_string method. Thanks for the reply though. – giriel Mar 04 '13 at 17:28
  • @giriel: the `from_string` is slightly special because of overload. Still well feasible though: `template struct Id {};` `template T from_string(std::string const& s) { return from_string(Id{}, s); }` and then you just need to define `MyEnum from_string(Id, std::string const& s);` for each `enum`. Obviously, this can be auto-generated code, for example generated by macros... – Matthieu M. Mar 04 '13 at 17:41
  • Aha thanks again, this solution is implemented and works. Although some changes were needed to make it work without c++11 support. This does not really solve the issue we presented but it is a good way to prevent the issue altogether. – giriel Mar 05 '13 at 12:35
  • @giriel: glad it solved your problem, could you indicate what issue you had without C++11 support for future reference ? – Matthieu M. Mar 05 '13 at 12:50
  • You cannot use the member operator on an enumeration :) – giriel Mar 05 '13 at 15:48