Hacker News new | ask | show | jobs
by thisisnotatest 3977 days ago
const is type-incompatible like this:

Suppose you want to write a function that returns all the nodes in a tree that satisfy some property. In C++ you have to define two different versions (or use templates to make the compiler clone it for you):

  vector<Node*> GetGoodNodes(Node* root);
  vector<const Node*> GetGoodNodes(const Node* root);
If more than one type is involved in the operation, there can be a combinatorial explosion.
2 comments

Yes, and what's wrong with that? You certainly don't want someone from the outside altering the nodes directly if you have an API which should be used instead.

Whenever I need to return a non-const reference/pointer to some inner data (which is not often) I name the method "mutableFoo()" to make clear what you're getting.

But most of the time (provided a sane API design) you won't have that problem anyway.

I don't feel that I understand purpose of this function yet.

Does this function return data point that it creates itself, or does it retrieve these nodes from somewhere else? If it's the first option, who's in charge of deleting them? If it's a second option, who's in charge of counting references to these objects? Also, if it's a second option, and this data points are retrieved from a certain storage, are you absolutely sure that whoever gets this data should be able to modify them?

> Does this function return data point that it creates itself, or does it retrieve these nodes from somewhere else?

It returns pointers to the nodes in the tree. You know this because the caller isn't supposed to (or allowed to) delete them, because if the caller was responsible for that, they'd be wrapped in smart pointers.

> If it's a second option, who's in charge of counting references to these objects?

The pointers in the return value are valid as long as their particular descendant of the function parameter isn't deleted. There's no need for reference counts, and if they're present at all, they aren't updated by this function, since the caller isn't responsible for decrementing them. If the caller was responsible, the return value would be a vector of smart pointers.

> Also, if it's a second option, and this data points are retrieved from a certain storage, are you absolutely sure that whoever gets this data should be able to modify them?

If they have a const node *, they shouldn't. If they don't, they should.

Thanks! Your first two answers would be obvious if we assume that we're working with modern codebase written by adequate developers, but that's a very strong assumption to make, so I wanted to be specific.

And your final answer is, well, exactly the point I was trying to steer the conversation to. In other words, if you declare both methods, it means that you're doing something wrong: you're giving away data mutably and immutably at the same time, and it just doesn't make sense.

You aren't.

If you have a non-const node, you can access its children non-constly _or_ constly (which you could do anyway, since you could make your reference to the node be const at any time). If you have a const node, you can only access its children constly.

This makes perfect sense.

My bad: didn't read the code carefully, thought that these were methods.
> if we assume that we're working with modern codebase written by adequate developers

Yeah, come to think of it if there's a chance this function came from a pre-C++11 codebase I wouldn't be so sure that the caller wasn't supposed to delete those nodes. Well, it'd be an odd thing for this particular function, I guess, but it's something I've seen or might have done, in general. In that case maybe I'd have had the function take an output parameter instead, in order to give it a scary variable name.