4 ms·
NB: If an argument to a function is a function pointer, you can write it like a normal function declaration. So you can write void transform_string(char s[]
by smitherfield 9y ago
NB: If an argument to a function is a function pointer, you can write it like a normal function declaration.
So you can write
void transform_string(char s[], char transform(char));
instead of having to write
void transform_string(char s[], char(*transform)(char));
When writing C++ you should use function references when possible, as references cannot be null.
void transform_string(char s[], char(&transform)(char));
Function references unfortunately require the more complex syntax, but fortunately C++11 `using`-style typedefs are quite simple to use with function types.
using TransformFunc = char(char, char);
typedef char TransformFunc(char, char); // C-style typedef, same as above
// Function pointer
TransformFunc fptr = /* ... */
// Function reference
TransformFunc &fref = /* ... */
- nybble41 9y ago"When writing C++ you should use function references when possible, as references cannot be null." Not true. You can still pass a dereference of a null pointer, which will create a null reference. The null is detected only when (if) the reference is used, not when the dereference expression is evaluated as an lvalue for its address to initialize the reference. char (transform_ptr)(char) = NULL; transform_string(s, transform_ptr); // no exception // ... later, in transform_string() ... transform(...); // exception
- smitherfield 9y agoYes, that's technically true, but you have to admit a little contrived, especially as pertaining to function pointers/references. I'll amend my statement to "unlike pointers, valid references cannot point to a null address." This is also true of any other language which has both nullable and non-nullable references, and a way to convert the former to the latter without accounting for the null case, such as Rust[1]. fn pass_null_reference() { unsafe { print_i32(&*std::ptr::null()) } } fn print_i32(n: &i32) { println!("{}", n) // segfault } [1] https://godbolt.org/g/1oUnNt https://godbolt.org/g/1oUnNt
- nybble41 9y agoAh, but what makes it an invalid reference, apart from convention? You could just as easily say that a null pointer is an invalid pointer in a context where a non-null value is expected. After all, a reference is just a constant pointer which is automatically dereferenced. Any program which may contain a null pointer may also contain a null reference. "This is also true of any other language which has both nullable and non-nullable references, and a way to convert the former to the latter without accounting for the null case, such as Rust." Indeed, though in Rust (like most other safe-by-default languages) you do need that glaringly obvious "unsafe" keyword to perform the conversion, which is a hint that you should be checking for null at that point.
- smitherfield 9y ago> Ah, but what makes it an invalid reference, apart from convention? It's an invalid reference in that a reference which does not refer to an object is either dead code, or an unrecoverable error. There's no point in checking if a reference refers to null, because (unlike pointers) it cannot then be assigned a useful value, and also because any such check will be removed by the optimizer, because null references are undefined behavior (in both C++[1] and Rust[2]). > Indeed, though in Rust (like most other safe-by-default languages) you do need that glaringly obvious "unsafe" keyword to perform the conversion, which is a hint that you should be checking for null at that point. It is an improvement but (obviously) the unsafety in this case escapes from the "unsafe" block into the surrounding "safe" code and other "safe" functions. It's also possible, even in entirely-"safe" code, to crash a Rust program by attempting to dereference a null pointer. fn dereference(nullable_ref: Option<&i32>) -> &i32 { nullable_ref.unwrap() } fn crash() { dereference(None); } [1] https://godbolt.org/g/TjexTp https://godbolt.org/g/TjexTp [2] https://godbolt.org/g/eeXAnn https://godbolt.org/g/eeXAnn
- steveklabnik 9y agoPanics are absolutey safe compared to segfault. “Memory safety” does not mean “this program never terminates unexpectedly.” You can also drop all the 'a business in that definition, it's superfluous.