1

If a class has an undefined pointer as a private variable, how to check if the pointer is valid if the observer function looks as follows:

Class Foo
{
  private:
    Object * object;
  public:
    Foo();
    virtual const Object & get_object() const { return * object; }
}
Ralff
  • 401
  • 2
  • 5
  • 15
  • 1
    I see you declared a constructor.... Any reason it can't be used to ensure the class invariants hold? – StoryTeller - Unslander Monica Jun 05 '18 at 04:53
  • 2
    You should set pointer to `nullptr` on construction, then you can check if it is null or not later. Obviously do not call `get_object` when it is null (or have that function throw) – M.M Jun 05 '18 at 04:53
  • 1
    The pointer is _uninitialised_ , not undefined. That means it could contain any value whatsover, what are you going to test it against? Moral: initialise _all_ your member variables in the constructor or by coding `Object * object = nullptr;`. – Paul Sanders Jun 05 '18 at 06:28

2 Answers2

2

In the constructor( in the initializer list ), you can set the Object *object as a nullptr

Foo::Foo()
:
object(nullptr)
{}

and in the get_object() method, make an if-check to ensure that the object is not null before dereferencing it :

if(object)
  return *object;
else
  // create and return a new Object depending on your use-case.
Vishaal Shankar
  • 1,648
  • 14
  • 26
  • Just did that. I was thinking along the lines of creating a new `Object` and returning, would have been better if the `class Object` was shown in the question. – Vishaal Shankar Jun 05 '18 at 05:20
  • I see the edit. Good improvement. `throw` should also be on the table, again depending on the use-case. – user4581301 Jun 05 '18 at 05:21
  • Is it possible to check though without modifying the observer? I am confused by how the returning a reference to the pointer works I suppose. – Ralff Jun 05 '18 at 05:26
  • @Ralff : Do you mean without setting object to `nullptr` ? again, are you confused about how dereferencing works ? It'll be great if you can try to be a tad more clearer. – Vishaal Shankar Jun 05 '18 at 05:33
  • @VishaalShankar Sorry, I am just wondering if it is possible check for the pointer being undefined without modifying the class Foo. – Ralff Jun 05 '18 at 05:36
  • @Ralff : You shouldn't be in a position to check if something is undefined. The reason it is called undefined is because you never know how the behavior would pan out to be. The ideal way to go about it is to personally make sure that your class does not lead to a UB case in any way. So, the correct thing would be to infact modify your `class Foo`. – Vishaal Shankar Jun 05 '18 at 05:56
  • You are trapped, @Ralff . You will have to modify `Foo`. you could take the address of the returned reference and see what you get before using it, but It is very hard to distinguish the junk address in an uninitialized pointer from a valid address. At the very least you will have to null `object` to park it at a safe and easily testable value. – user4581301 Jun 05 '18 at 05:56
  • @user4581301 : OP can do that, but the problem with UB would be that it just can't be trusted. – Vishaal Shankar Jun 05 '18 at 05:59
  • 1
    You are correct sir. Reference must be valid object and NULL is explicitly called out by the standard as verboten. I have clearly been abusing illegal pharmaceuticals. – user4581301 Jun 05 '18 at 06:07
  • Strictly speaking, `get_object()` is not dereferencing `object`. It's UB, if `object` is `nullptr`, but it [doesn't crash](http://coliru.stacked-crooked.com/a/189d38732013ed0b). – Paul Sanders Jun 05 '18 at 06:56
1

I think we have all misunderstood the OP's problem here, and that includes me. OK, he has failed to initialise object, but, if I read this right, that's not what he's asking about. He wants to know, I believe, how a reference can 'point to' an invalid object.

Well, normally it can't. The contract, when return a reference, is that it will always point to something valid, and specifically will not, under the covers, contain nullptr. That's why you return a reference, and not a pointer. Because it carries that guarantee.

So, has @Ralff painted himself into a corner? Well, not quite. The usual solution of course would just be to have get_object() return a pointer in the first place, but he evidently doesn't want to do that.

A good solution here is to keep an object of type Object around that serves as a placeholder for an invalid object. Then it's easy. I'll stop waffling and post some code:

#include <iostream>

class Object
{
    // ...

public:
    static Object invalid_object;
    bool is_valid () const { return this != &invalid_object; };
};

Object Object::invalid_object;

class Foo
{
private:
    Object * object = nullptr;
public:
    Foo() { }
    virtual const Object & get_object() const { return (object) ? *object : Object::invalid_object; }
};

And now you can do:

int main ()
{
    Foo foo_obj;
    const Object& obj = foo_obj.get_object ();
    if (obj.is_valid ())
        std::cout << "object is valid" << std::endl;
    else
        std::cout << "object is invalid" << std::endl;
    return 0;
}

Live demo.

OP, for other approaches, check out also std::optional, or consider throwing an exception from get_object() (although that would not be my choice).

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48