Hacker News new | past | comments | ask | show | jobs | submit login

Abstracting the ownership behind an interface presumably is needed when the ownership model is very complex. From my experience this is nothing but a big red flag. If you need a class to manage an ownership, it means that you can't easily trace its movement, in which case it means that it is a total bitch to debug, leave alone being able to read through the code and understand where that damn ownership is at any given moment.

I know it's beautiful language with a laundry list of features, but keeping things simple is still the best approach:

  #define __no_copying(type)                      \
                                                  \
	private:                                  \
		type(const type &);               \
		type & operator = (const type &); \
	public:

  class foo
  {
  public:
        foo();
        __no_copying(foo);
  ...
  }
In a spaghetti-less code this typically applies in 99% of all cases. There's a remaining 1%, which it's easier and cleaner to handle on a case by case basis.



Even better:

  class foo : boost::noncopyable
  {
  public:
    foo();
  };


Oh, jeez. Don't get me started on that Boost thing, comrade.


boost has many problems, but I think not using any of it just because some parts of it are bad isn't very useful.

In this particular example it is very easy to screw it up. Your way involves many more lines of code and use of the preprocessor which makes searching through code very difficult. I can easily find all the noncopyable classes by searching for "noncopyable". I don't have to worry about someone coming along and screwing up the access modifier at a later date. It is much less likely that someone will misunderstand what the code is trying to do, even if they don't know much about C++ value semantics.

Edit: I guess my criticism regarding searching isn't valid here, but I have come to try and avoid the preprocessor as much as possible. I've just been bitten by it too many times.

  class Noncopyable
  {
  private:
    Noncopyable(const Noncopyable&);
    Noncopyable& operator(const Noncopyable&);
  };
That's pretty much was boost::noncopyable is, and it's the same thing you wrote, but it removes the preprocessor.


> it is very easy to screw it up

No, it's not. This just a made-up argument.

> ... many more lines of code

6 in #define, one of which is blank. Your option however creates an external dependency on the library that somehow needs to be built even though it is supposed to be just a collection of headers.

> ... and use of the preprocessor which makes searching through code very difficult

Ok, considering your Edit, let's skip this one.

> I can easily find all the noncopyable classes by searching for "noncopyable".

Similarly, you can find all noncopyable classes by searching for "__no_copying". Besides, why on Earth you would ever need to do that in real life?

> I don't have to worry about someone coming along and screwing up the access modifier at a later date.

Ah, right. Here we start to really diverge. You are writing code that needs to be protected against incompetent colleagues, and I typically don't.

> It is much less likely that someone will misunderstand what the code is trying to do

No, of course it is not. This is too a made-up argument.

PS. I hate Boost with passion, because it drags C++ in the exact opposite direction from how I am, personally, using it, which is C with classes, uncomplicated inheritance and basic templating. This is beautiful and functional subset of C++ that retains the clarity of C and adds flexibility and convenience that latter is missing. Boost has its place, clearly, but I don't understand programmers who willingly use it, just as I don't understand those who like Bjork.


I have seen this screwed up time and time again. People who don't know how all this works shouldn't be writing C++, but they do and I have to deal with the things they break. Most of my code isn't broken by incompetent colleagues, it's incompetent clients that use the code. Maybe the experience is different when you're writing commercial libraries which is what I've been doing for the past few years.

I guess you and I have had vastly different experiences. boost has improved my code immeasurably. I cannot stand the "C with classes" approach. All the code I've come across the uses that approach is always broken in subtle ways the could be avoided by using the simple utilities in boost. I think in the end it is probably just personal preference.

I'll agree with you about Bjork. But I am a serious musician and the best musician I have every been in the presence of loved Bjork.


Ya, and in my humble opinion / coding style (everyone's got one...) it's not too hard to just add the

foo(const foo &);

foo & operator = (const foo &);

to every class definition that needs it. Small amount of basic, simple C++ boilerplate > magic.


Agree in the main. Even before smart_ptr's were integrated into the standard, bespoke versions that appeared to some to remove scoping confusion had a tendency to propagate like weeds. In the majority of cases, const correctness, mutability if needed and good scoping concepts removed redundant reference counting run time garbage.

On one project I worked on as a contractor, and quite a large one at that, I removed every single one of them and rescoped the code base. It took a while but performance alone improved by about 400%


I'll say this just once: smart pointers and reference counting are not the same thing, and neither of them implies the other.


Didn't need to say it at all. I probably wasn't being clear enough but I was referring to early versions that were called smart precisely because they removed the need for the programmer to count because they counted themselves. Hence 'smart'. Before boost and others cleaned it all up.

As others are pointing out they have advantages and disadvantages. It all depends on the situation. But they're certainly not free because they have a scope cost. Code size and simplifying compiler optimisation are important too. I think it's worth that pointing out.


the lesson there was not that every programmer needs to painstakingly thing through every detail of scope management, it's that the problem needed to be solved comprehensively and integrated into the standard library.


That was one lesson. There were others as well, and they're related. It was a temptation to believe that they were a kind of magic bullet that acted as a scoped resource scavenger. Mostly vtable jump resource cleanups through dtors in the usual way.

Unfortunately it was slow, and as others have mentioned, sometimes difficult to debug and heap errors can propagate out of order, depending on other conditions.

I'm in no doubt about the value of the auto_ptr variants. However I'm often brought in to speed up projects that don't meet performance requirements, and it often entails rethinking structure, simplification, replacing generalised ctor dtor lists, and rediscovering where const references, independently of move semantics, lead to algorithmic questions that need reexamining. This leads back to encompassing scope, and from there it's often the right thing to institute a better model.

The benefit can be a lot less instructions and resultant speedups.

Perhaps I've had too many of these jobs, but hey, it's a living.


I disagree. “unique_ptr” and “shared_ptr” both model very simple ownership policies, yet there is still value in separating them from the objects whose lifetimes they manage. The value is in their composability—a programmer can rely on “unique_ptr” to do the right thing automatically, in a manner enforced by the type system. When writing C++ code, I spend an irritating proportion of my time navigating the minefield—it’s well worthwhile to encapsulate some of those details.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: