3

I have developed a habit of using safe C++ constructs where possible, but there is one place where I'm always not sure if it's better to use references or resort to good ol' pointers.

Example code:

int FillFancyPointer(char *&ptr)
{
    ptr = NULL;

    char *tmp_ptr = static_cast<char*>(calloc(...));
    if(!ptr)
        return -1;

   ptr = tmp_ptr;
   return 0;
}

Later in code:

char *ptr = nullptr;
if(FillFancyPointer(ptr)>=0 && ptr)
   Nice();

The problem with this, IMHO, is that the ptr appears to be read only variable when looking at the code, while in reality it is modified.

The COM approach ISmthn *ptr;, CoCreate(..., &ptr) seems more pronounced. But it's also more error prone, as there is this ** stuff everywhere.

Come to think of it, output variables like std::string will also be masked with such approach.

int Foo(const string &in, string &inout)

Do you find references confusing in such places?

8
  • 1
    What's going on in this code, anyway? It's a reference to a pointer, or a pointer to a reference, or something else? Dec 13, 2011 at 19:22
  • 1
    Right to left reading, ptr is a reference to pointer of type char.
    – Coder
    Dec 13, 2011 at 19:31
  • Just curious: Is there really a situation where this approach is warranted? It seems like there should be an more understandable way to solve the problem...? Dec 13, 2011 at 19:54
  • Slowly C++'izing a C style code... You slowly migrate away from C issues like *p[i] = b; / **p = b; / etc. at the same time having the transition period to shared_ptr<char> etc. which is incompatible with the codebase without larger code changes.
    – Coder
    Dec 13, 2011 at 20:00
  • 1
    @kevincline: It was a hypotetical problem :D What if you could return 2 if the pointer is the same, just reallocated, and so on. The question is still, if such parameter modifications are bad or good as they are quite invisible in the code.
    – Coder
    Dec 14, 2011 at 19:47

3 Answers 3

4

The problem with your code sample isn't that you take a reference, it's that you use a return code. In C++, if the operation fails, throw an exception, or if that isn't unusual, then use boost::optional, or even boost::variant<T, ErrorCode>.

Your code is very C and not C++ at all.

2
  • Old code maintanance & C++ifying... Although exceptions are not very good IMHO, a whole new can of worms...
    – Coder
    Feb 24, 2012 at 4:26
  • @Coder: Exceptions suck. But they're one hell of a lot better than error codes.
    – DeadMG
    Feb 24, 2012 at 4:28
2

If you’re concerned about mutability, make references const unless they need to be mutable, and leave it at that. A function’s name and documentation should convey its purpose and whether it intends to modify one of its parameters.

Users of the function shouldn’t need to care whether something is passed by value or reference; the “invisibility” of references—that they have the same syntax as values—is one of their strengths. The reason for introducing references to C++ in the first place was to “invisibly” support operator overloading. In addition to their consistency, they are also amenable to generic programming, which is a big thing in the C++ world. And in C++0x, it gets more interesting: you can pass variables syntactically by value, but they can be move-constructed, eliminating the need for a copy.

1
  • Well, move construction is usually natural, the copy construction has issues, because copy constructors usually have side effects, like copying buffers, sharing shared states etc. And unexpected behavior for move constructor is not really unexpected, vs sudden change in values passed by reference.
    – Coder
    Dec 13, 2011 at 19:54
1

Everything about your code example is C and not C++. I think you have bigger issues than whether you are passing a pointer by reference or not. For example, I would suggest using new and delete rather than malloc.

To answer you question directly, use references everywhere you can and pointers when you have to - ie when you need to reseat the reference. All of this is in the C++ FAQ which is a mine of brilliant information.

1
  • I actually prefer malloc/calloc/realloc/free over new/placement new/delete. The downside is that constructors are not called for C variants.
    – Coder
    Feb 24, 2012 at 4:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.