Quantcast
Channel: Active questions tagged gcc - Stack Overflow
Viewing all articles
Browse latest Browse all 21994

C++ incorrect constructor order in gcc compiling static members in generic class

$
0
0

The constructor order problem

I have probably faced a bug in gcc compiler when I was solving a problem of making an arbitrary trait of a class like ThorsSerializer does, but more generic. Moreover I am not sure how to report such an error. I have tried following gcc versions 7.6, 8.2, 9.2. Here is the minimal code presenting the problem I have ran into:

#include <iostream>
#include <string>

struct Member{
    std::string s;
    Member(){std::cout <<"Member constructor: "<< s << std::endl;}
};

template<typename StatMemberType>
class Message {

public:

    static StatMemberType s;

    Message(const std::string& message){
        s.s = message;
        std::cout << "Message constructor s.s: "<< s.s << std::endl;

    }
    static std::string& getMessage() {return s.s;}

};
template <typename StatMemberType> StatMemberType Message<StatMemberType>::s;


/**
The class MessageHello creates a global instance of Message saying Hello
*/
template <typename dummy>
class MessageHello {
public:
    static Message<Member> message;
    MessageHello() {std::cout << "MessageHello constructor message.getMessage(): "<< message.getMessage() << std::endl;}
};
template <typename dummy> Message<Member> MessageHello<dummy>::message("Hello");


void testConstrucorOrder() {

    std::cout << "global value of MessageHello: "<< MessageHello<void>::message.getMessage() << std::endl;
}

int main()
{
    testConstrucorOrder();
    std::cout << "\nthe expected output:\n";
    std::cout << "Member constructor:\nMessage constructor s.s: Hello"<< std::endl;
    std::cout << "global value of MessageHello: Hello";
}

The output of this code using gcc compiler is:

Message constructor s.s: Hello
Member constructor: 
global value of MessageHello: 

But I wanted to obtain this: (When I try to compile this example with clang 5.0, the obtained result is as desired.)

Member constructor:
Message constructor s.s: Hello
global value of MessageHello: Hello 

The incorrect order of constructing the elements causes resetting of the attribute Member after the value was set in constructor of class Message. Thus, the global value of MessageHello is empty.

My solution

I would like to ask whether my solution using Singleton class to preserve the correct order of constructors is ok? The solution reads:

#include <iostream>
#include <string>
#include <memory>
/**
 * @brief The Singleton class
 */
template<class Class>
class Singleton {
public:
    static Class& getInstance(){
        if (p == nullptr) {
            p = std::unique_ptr<Class>(new Class); // the class must be trivially constructible
        }
        return *p;
    }
protected:
    static std::unique_ptr<Class> p;
    Singleton() {}
private:
    // disable move and copy options
    Singleton(Singleton const&) = delete;
    Singleton(Singleton const&&) = delete;
    Singleton& operator=(Singleton const&) = delete;
    Singleton& operator=(Singleton const&&) = delete;

};
template <class Class> std::unique_ptr<Class> Singleton<Class>::p = nullptr;


struct Member{
    std::string s;
    Member(){std::cout <<"Member constructor: "<< s << std::endl;}
};

template<typename StatMemberType>
class Message {

public:

    Message(const std::string& message){
        Singleton<StatMemberType>::getInstance().s = message;
        std::cout << "Message constructor Singleton<StatMemberType>::getInstance().s: "<< getMessage() << std::endl;

    }
    static std::string& getMessage() {return Singleton<StatMemberType>::getInstance().s;}

};


/**
The class MessageHello creates a global instance of Message saying Hello
*/
template <typename dummy>
class MessageHello {
public:
    static Message<Member> message;
    MessageHello() {std::cout << "MessageHello constructor message.getMessage(): "<< message.getMessage() << std::endl;}
};
template <typename dummy> Message<Member> MessageHello<dummy>::message("Hello");


void testConstrucorOrder() {

    std::cout << "global value of MessageHello: "<< MessageHello<void>::message.getMessage() << std::endl;
}

int main()
{
    testConstrucorOrder();
}

This code works correctly even when compiled by gcc.

Member constructor: 
Message constructor Singleton<StatMemberType>::getInstance().s: Hello
global value of MessageHello: Hello

Viewing all articles
Browse latest Browse all 21994

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>