1

I have a std::map container variable in my class that is populated with objects of my nested-class:

class Logger {
private:
//...
    class Tick{
        ///stores start and end of profiling
        uint32_t start, lastTick,total;
        /// used for total time
        boost::mutex mutexTotalTime;
        ///is the profiling object started profiling?
        bool started;
    public:
        Tick(){
            begin();
        }
        /*
        Tick(const Tick &t){
            start = t.start;
            lastTick = t.lastTick;
            total = t.total;
            started = t.started;
        }
        */
        uint32_t begin();
        uint32_t end();
        uint32_t tick(bool addToTotalTime = false);
        uint32_t addUp(uint32_t value);
        uint32_t getAddUp();

    };
    std::map<const std::string, Tick> profilers_;
//...
public:
//...
Logger::Tick & Logger::getProfiler(const std::string id)
{
    std::map<const std::string, Tick>::iterator it(profilers_.find(id));
    if(it != profilers_.end())
    {
        return it->second;
    }
    else
    {
        profilers_.insert(std::pair<const std::string, Tick>(id, Tick()));
        it = profilers_.find(id);
    }
    return it->second;
}
//...
};

the above code will not compile if I dont provide a copy constructor while I thought the default copy constructor should be already in place?! Am I missing any concept? thanks

rahman
  • 4,820
  • 16
  • 52
  • 86

3 Answers3

3

The copy constructor may be generated for you only if all members of your class are copyable. In the case of Tick you have an object

boost::mutex mutexTotalTime;

which is not copyable, so the compiler will not generate the copy constructor. Observe that in your commented out copy constructor you do not copy the mutex - because you know you should not. The compiler does not know that.

As a side note, there is no need to explicitly say const for map keys:

std::map<const std::string, Tick> profilers_;

Map keys are always const, and your declaration is completely equivalent to

std::map<std::string, Tick> profilers_;
Wojtek Surowka
  • 20,535
  • 4
  • 44
  • 51
2

boost::mutex is non-copyable. Since Tick has one as a data member, this makes Tick also non-copyable. This in turn makes the map non-copyable.

So to make Logger copyable, you have to provide your own copy constructor and implement an appropriate duplication of profilers_ in it. Or, perhaps even more appropriately (thanks to @LightnessRacesInOrbit for the suggestion), provide an appropriate copy constructor for Tick instead.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
2

The problem is that boost::mutex is not copyable. So if you don't provide a copy constructor, the compiler attempts the generate a default one. That default one needs to copy all of the members, but cannot copy boost::mutex, so it gives up. Your copy constructor does not copy the mutex. Instead it default initializes the new one, so this works.

Stewart
  • 3,978
  • 17
  • 20