Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I haven't done much programming in C++, so I figured I'd try making an Optional class. I'm mainly concerned that I didn't follow good conventions or that I didn't use exceptions well. I know that there are no comments, but for now, let's ignore that.

The idea is that my Optional class can be used instead of pointers and nullptr when I need to return an optional value.

optional.h

#pragma once

namespace extra { // I'm putting random library classes/functions in this namespace
    template <typename T>
    class Optional
    {
    public:
        const static Optional<T> empty;
        static Optional<T> of(const T &v);
        static Optional<T> of(T *v);
        T get() const;
        bool hasValue() const;
        ~Optional() { if (value != nullptr) delete value; }
    private:
        Optional(T *v) : value{ v } {}
        const T *value;
    };

    template<typename T>
    const Optional<T> Optional<T>::empty = Optional::of(nullptr);

#include "optional.impl"
}

optional.impl

#include <stdexcept>

template<typename T>
Optional<T> Optional<T>::of(const T &t) {
    return Optional<T>{ new T(t) };
}

template<typename T>
Optional<T> Optional<T>::of(T *t) {
    if (t != nullptr) return Optional<T>{ new T(*t) };
    return Optional<T>{ nullptr };
}

template<typename T>
bool Optional<T>::hasValue() const {
    return value != nullptr;
}

template<typename T>
T Optional<T>::get() const {
    if (!hasValue()) throw std::runtime_error("Tried to get the value from an optional that has no value");
    return *value;
}

template<typename T>
bool operator==(const Optional<T>& t1, const Optional<T>& t2) {
    if (!t1.hasValue() && !t2.hasValue()) return true;
    else if (!t1.hasValue() || !t2.hasValue()) return false;
    return t1.get() == t2.get();
}

template<typename T>
bool operator!=(const Optional<T>& t1, const Optional<T>& t2) {
    return !(t1 == t2);
}
share|improve this question
up vote 1 down vote accepted

Rule of Three.

int main()
{
    extra::Optional<int> x = Optional<int>of(new int(5));
    extra::Optional<int> y(x);   // This still compilers.

    // But your problems don't appear until here
    // at the end of scope.
}

Design

Why do you force the construction of optional objects via the static methods?

    static Optional<T> of(const T &v);
    static Optional<T> of(T *v);

Why not allow people to just construct the objects in the normal way. It would seem more natural to create objects of this type just like any other object!

Move semantics

You may not want copy semantics (since you are basically implementing a smart pointer. But you could do with implementing move semantics on your object.

Overall

I don't see the need.

If you want to return a pointer (but make sure it is managed). Then pass back a std::unique_ptr<T>.

If you are doing this as a learning exercise that's different. I'll give it a good going over once you have fixed the problems around the rule of three. But that is such a fundamental problem there is no point in reviewing this code further (Though in future version I would like a justification for the static of() methods and examples of why they are needed).

share|improve this answer
    
I have no idea why I did the static of methods. But I don't understand why such a class is not "needed". Java has an Optional<T> class, as well as many other languages. The idea is that the class communicates more than a simple pointer (which could be null). What does nullptr mean anyways? For an Optional, it would simply mean that the value is not present. – Justin Sep 4 '15 at 20:22

Your question is a little unclear. Should this class be used to indicate an error in a function that should return some value? For example:

auto do_something() -> optional<int> { ... }

auto main() -> void {
    auto i = do_something();
    if (i.hasValue()) {
        // do_something() was ok.
    }
    else {
         // error case
    }
}

If this is the intention you may want to read https://github.com/ptal/std-expected-proposal for things to consider.

Also you may want to add a de-reference and boolean operators letting you do the following:

auto i = do_something();
if (i) {
     // success case
     int value = *i;
}

Doesn't make your code more correct but is less to type! I can provide my version of a similar class if it will help.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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