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?
3 Answers 3
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.
-
Old code maintanance & C++ifying... Although exceptions are not very good IMHO, a whole new can of worms...Coder– Coder2012年02月24日 04:26:37 +00:00Commented Feb 24, 2012 at 4:26
-
@Coder: Exceptions suck. But they're one hell of a lot better than error codes.DeadMG– DeadMG2012年02月24日 04:28:28 +00:00Commented Feb 24, 2012 at 4:28
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.
-
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– Coder2011年12月13日 19:54:09 +00:00Commented Dec 13, 2011 at 19:54
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.
-
I actually prefer
malloc
/calloc
/realloc
/free
overnew
/placement new
/delete
. The downside is that constructors are not called for C variants.Coder– Coder2012年02月24日 04:28:36 +00:00Commented Feb 24, 2012 at 4:28
*p[i] = b; / **p = b; / etc.
at the same time having the transition period toshared_ptr<char>
etc. which is incompatible with the codebase without larger code changes.