7

I find that making a class non-copyable helps me a lot with my code quality. Initially I did this with boost::noncopyable, but I found the VC++ compiler errors to be not as helpful as with private members (double clicking lead to the wrong place in the code).

T(T const&);
T& operator=(T const&);

Indeed, it has alerted me to quite a few cases were classes were not passed as reference where they should have. So much so, that I would very much like to get a warning even on classes that I just need to copy construct once.

Is there a good way to do this? I was thinking for example of leaving above two methods private and adding a public T(T const&,bool dummy) constructor to call when I really want to copy construct. Or maybe alternatively make above two methods public and somehow activate a compiler warning when copy constructing, suppressing the warning where I do want to.

Or maybe there is an all together better way?

Cookie
  • 12,004
  • 13
  • 54
  • 83

4 Answers4

6

Not sure if it's exactly what you want, but if you mark the copy constructor explicit then the class can't be passed by value or copy-initialized, but you can copy-construct using direct initialization.

You'd presumably want to keep the assignment operator private, maybe a NonAssignable base would be useful for that.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 1
    I like this answer best. The problem with copy constructors, in my experience, is when they get invoked "by accident" on some huge object. `explicit` forces you to think about it when you invoke them, which should be sufficient. – Nemo Jul 07 '11 at 21:28
  • Cheers, this perfectly suits my needs. Thanks. – Cookie Jul 16 '11 at 22:39
2

I think you named a perfect way there yourself.

I just remembered a neat(?) little trick I once played in another code base I worked on:

struct T
{
    friend class SomeClientThatCanConstructT;
    T(T const&);

  private:
     T(T const&);           
};

As discussed in the comments the following won't fly

You might opt for an explicit name (like CopyConstruct) and rely on RVO to be equally efficient:

struct T
{
     inline T CopyConstruct() const     { return *this; }
     inline T& AssignTo(T& dst) const   { return dst = *this; }
     inline T& AssignFrom(const T& src) { return *this = src; }

  private:
     T(T const&);
     T& operator=(T const&);
};

sehe
  • 374,641
  • 47
  • 450
  • 633
  • I thought about this but your `CopyConstruct` requires that the copy constructor be accessible even if the compiler doesn't call it. – Mark B Jul 07 '11 at 19:01
  • Shute. Thanks for reminding me. This is indeed a stopper. Of course you can uglify it all the way, but for the constructor call, there really is no alternative to your 'tag parameter' solution. Come to think of it, I suddenly remember doing this myself... Updating answer – sehe Jul 07 '11 at 19:15
  • Why do you need `private_tag`? Can't the friend class just invoke the private copy constructor directly? – Nemo Jul 07 '11 at 21:27
  • @Nemo: I was misremembering things. Apparently one can be too busy for SO... I found the spot in the old codebase and it turned out I had only been using the tag to detect lingering usages of the default constructor when migrating a class to be a singleton. Don't know why I jumped to the conclusion that it would help here :) – sehe Jul 07 '11 at 21:45
0

You could possibly default construct a T and then add an assign method to use. This doesn't seem fully optimal though, indicating that you might want to review your copying needs.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

I don't like the idea of restricting a type (CopyConstructible is a heavily used concept throughout the stdlib) because it might be misused. If you can construct an object from another instance, it should be copy constructible. It also distracts the reader from the important code without serving any real purpose.

Maybe a warning or assertion in debug mode that is triggered by the copy constructor is really what you are looking for?

pmr
  • 58,701
  • 10
  • 113
  • 156
  • Is there such a thing? e.g. could I define a user defined warning whenever the compiler or linker links to a function? and then suppress the warning in the object file I want? Like a pragma warning disable? – Cookie Jul 08 '11 at 12:01