1

I have a class with an optional field declared of void const * (I'm also confused if to * outside the angle brackets or inside.

class Test { protected: std::optional<void const> *_data; // void const *_data public: explict Test(void const *data = nullptr); } 

In the Test.cpp file.

Test(const void *data) { this->_data = data; // error } 

enter image description here

16
  • 1
    Please specify your exact, verbatim error. Commented Dec 22, 2021 at 0:38
  • 1
    void const* is also equivalent to const void*. const in a type specifier refers to the "thing" to the left of const, except in the special case where the "first" thing in your type should be const, and you can place const to either the left or right of it. I think this is just for readability - maybe backwards compatability. Someone else can speak on the historical reasons. I personally prefer const void* to void const*, but you can find both in the wild. It's just a style thing. Commented Dec 22, 2021 at 0:40
  • 1
    now that you made the clear with the comparison of void const* and const void*, I also prefer const first, because this is what i have been used to in other languages. Thanks. Commented Dec 22, 2021 at 0:45
  • 1
    its the responsibility of the caller of the function to check for the null for the returned value correct - which your user would have to do with a std::optional anyway. Now, another option is to specify that it's "undefined behavior" or "illegal" for a user of your class to construct it with a nullptr. And that it's not a valid state for the object to exist with a nullptr sitting inside of it. That puts the responsibility on the "creator" of the object, and not the "user" (even though they're likely the same human). This all depends on whether it's valid for your _data to be nullptr Commented Dec 22, 2021 at 0:52
  • 1
    constexpr static char const *const NAME = "Test"; is a const pointer (the value of the pointer shall not be changed) to a const char (the value of the chars in the array shall not be changed). The constexpr makes some of this redundant, since constexpr implies const anyway. Commented Dec 22, 2021 at 0:59

1 Answer 1

3

In your example, where _data is a non-const pointer to a std::optional (it doesn't matter that the std::optional holds a const void type), you're trying to assign a pointer to a const object (of unknown void type) to a non-const pointer.

This violates the contract of your class constructor, where you promise not to modify the object being pointed at (not just in the constructor, but ever). Consider this simplified example:

template <typename T> Test { protected: T* _data; public: explict Test(const void * data = nullptr) { _data = data; // ERROR: can't assign a const-pointer to a non-const pointer } } 

Your issue has nothing to do with std::optional.

Consider that you might not even need to wrap your pointer in a std::optional, since pointers already have the natural nullable-concept of nullptr:

class Test { protected: const void* _data; public: explict Test(void const *data = nullptr) { _data = data; } void do_thing() const { if (_data) { // nullable semantics naturally work on pointers, no need for `std::optional` // UNLESS `nullptr` isn't "null enough" for your application // do (const-qualified) operation on _data. } } } 

On the concept of std::optional, pointers, and nullable

it's the responsibility of the caller of the function to check for the null for the returned value

correct - and your user would have to do with a std::optional anyway.

Another option is to specify that it's "undefined behavior" or "illegal" for a user of your class to construct it with a nullptr. And that it's not a valid state for the object to exist with a nullptr. That shifts the responsibility on the "creator" of the object, and not the "user" (even though they're likely the same human). This all depends on whether it's valid for your _data to be nullptr.

Decide what the valid states of your object are allowed to be, and whose responsibility it is to enforce that. If you design your interface correctly, you can eliminate a lot of if checks that would otherwise need to be scattered throughout all layers of the code.

Some of the responsibility lives with the object creator (user), some of the responsibility lives within the class (this could be shared with the user-creator for validity checks, or ignored), and some lies with the object user (application developer).

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.