2
\$\begingroup\$

Relatively new to C++, not sure if I'm doing everything right, any advice would be appreciated. The site does not allow me to post this question with that little actual text, so I am artificially extending it with this dummy text. Here's what I wrote:

#include <iostream>

template<typename T>
class DefaultPointer {
    const T* value_pointer;
    const T default_value;

public:
    DefaultPointer(const T* ptr, const T& def) : value_pointer(ptr), default_value(def) {

    }

    const T get() {
        if (value_pointer == nullptr) {
            return default_value;
        }
        return *value_pointer;
    }
};

template<typename T>
class Default {
    const T value;
    const T default_value;

public:
    Default(const T& value, const T& def) : value(value), default_value(def) {

    }

    const T get() {
        if (!(bool)value) {
            return default_value;
        }
        return value;
    }
};

int main() {
    const int test_value = 1;
    const int* const pointer = &test_value;
    std::cout << DefaultPointer<int>(pointer, 0).get();
}
\$\endgroup\$
1
  • \$\begingroup\$ get() is not very idiomatic c++. Prefer operator *(). \$\endgroup\$
    – vnp
    Jan 25 at 5:17

1 Answer 1

2
\$\begingroup\$

Here are some considerations:

  1. Use of const:

    • In your DefaultPointer and Default classes, the get method does not modify any member variables, so it's good practice to mark it as const to indicate that calling this method won't change the object's state.
    • For the member variables value_pointer and value, consider if you really want them to be const. This makes your objects immutable after they're constructed, which might be your intention. If you ever need to change the pointer or value after construction, you'll need to remove the const.
  2. Checking for null pointers and zero values:

    • In Default, you check if (!(bool)value). This works for numeric types where 0 is implicitly convertible to false, but it might not be clear or applicable for all types T. Consider if there's a more explicit or type-safe way to handle this, depending on what types you expect T to be.
  3. Return Type Optimization:

    • Returning by const T is unusual. Typically, you'd return by value (T) or by const T& if you're returning a reference to an existing object (to avoid copying). Returning by const T prevents the caller from modifying the returned value, which is unnecessary for built-in types and might inhibit move semantics for user-defined types.
  4. Error Handling:

    • Consider what should happen if an invalid pointer is passed to DefaultPointer. Your current implementation gracefully handles nullptr, but what about dangling or uninitialized pointers? This might be beyond the scope of your current practice but is worth thinking about as you advance.
  5. Usage Example:

    • Your main function demonstrates usage of DefaultPointer but not Default. It might be beneficial to include an example of how Default is intended to be used, especially considering its reliance on the boolean conversion of T.
  6. Other practices to keep in mind:

    • If you're using C++11 or newer, you can use nullptr instead of NULL for null pointer constants. It's more type-safe and clear.
    • Consider using smart pointers (std::unique_ptr, std::shared_ptr) if you plan to work with dynamically allocated memory. They help manage memory more safely and automatically.
\$\endgroup\$
2
  • \$\begingroup\$ I do actually expect the parameter of Default to have a bool operator. I now have a question: how do I check for a dangling or an uninitialized pointer? And is there a way that is considered a good practice for such a check? \$\endgroup\$ Jan 25 at 6:30
  • \$\begingroup\$ There isn't a fullproof method to checking or I don't think there is \$\endgroup\$
    – 37307554
    Jan 25 at 6:37

Your Answer

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

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