Skip to content
Snippets Groups Projects
Commit f3e1d137 authored by Eric Elfving's avatar Eric Elfving
Browse files

Filer från 2018-03-20

parent 2471fc47
No related branches found
No related tags found
No related merge requests found
Showing
with 12660 additions and 0 deletions
......@@ -5,4 +5,8 @@ Detta repo fylls på med exempelkod från föreläsningarna.
| Fil / Katalog | Beskrivning | Datum |
| ------------- | ----------- | ----- |
| STL-Intro | Visar ett litet exempel löst på flera olika sätt för att introducera standardbiblioteket | 2018-03-19 |
| ptr.cc | Kort exempel på smartpekare (i form av ```unique_ptr```) | 2018-03-20 |
| sum.cc | En enkel mallfunktion för att addera två värden av någon typ | 2018-03-20|
| push.cc | En mallfunktion som anropar ```push_back``` på någon angiven container | 2018-03-20 |
| optional | En klass för att hantera (eventuell avsaknad av) ett värde. Implementeras först för int men anpassas sedan som en mall (template). | 2018-03-20 |
CC=g++ -std=c++17 -Wall -Wextra -pedantic
basic: optional_basic/optional.cc optional_basic/optional.h optional_basic/optional_test.cc test_main.o
$(CC) -I. -I optional_basic optional_basic/optional.cc optional_basic/optional_test.cc test_main.o -o $@
unique_ptr: optional_unique_ptr/optional.cc optional_unique_ptr/optional.h optional_unique_ptr/optional_test.cc test_main.o
$(CC) -I. -I optional_unique_ptr optional_unique_ptr/optional.cc optional_unique_ptr/optional_test.cc test_main.o -o $@
template: optional_template/optional.tcc optional_template/optional.h optional_template/optional_test.cc test_main.o
$(CC) -I. -I optional_template optional_template/optional_test.cc test_main.o -o $@
test_main.o: test_main.cc catch.hpp
$(CC) -c test_main.cc
# A simple implementation of std::optional
## Lecture example from 2018-03-20
Three versions; basic has a memory leak (no destructor) and this is fixed with a smart pointer in ```unique_ptr```. Lastly we have a template version.
All can be compiled using make. Just run ```make basic```, ```make unique_ptr``` or ```make template```.
Source diff could not be displayed: it is too large. Options to address this: view the blob.
#include "optional.h"
#include <utility>
Optional::Optional(int i)
: data{new int{i}}
{}
Optional::Optional(Optional const & o)
{
if (o.has_value())
{
data = new int{*o};
}
}
Optional & Optional::operator=(Optional const & o)&
{
Optional{o}.swap(*this);
return *this;
}
Optional & Optional::operator=(int i)&
{
if ( !has_value() )
{
data = new int{};
}
*data = i;
return *this;
}
Optional::Optional(no_value_t) noexcept: data{} {}
Optional& Optional::operator=(no_value_t) noexcept
{
reset();
return *this;
}
int & Optional::value()
{
if ( !has_value() )
throw no_value_error{"No value!"};
return *data;
}
int const & Optional::value() const
{
if ( !has_value() )
throw no_value_error{"No value!"};
return *data;
}
Optional::operator bool() const
{
return has_value();
}
bool Optional::has_value() const
{
return data != nullptr;
}
int const & Optional::operator*() const noexcept
{
return *data;
}
int & Optional::operator*() noexcept
{
return *data;
}
void Optional::swap(Optional & o)
{
using std::swap;
swap(data, o.data);
}
void Optional::reset()
{
delete data;
data = nullptr;
}
#pragma once
#include <stdexcept>
struct no_value_t {} inline const no_value{};
class Optional
{
public:
Optional() = default;
Optional(Optional const & o);
Optional & operator=(Optional const & o) &;
// initialize from underlying type
Optional(int i);
Optional & operator=(int i) &;
// Set to no_value
Optional(no_value_t) noexcept;
Optional & operator=(no_value_t) noexcept;
// accessors. value throws when unset, dereferencing unset value is undefined
int & value();
int const & value() const;
int & operator*() noexcept;
int const & operator*() const noexcept;
// checker
explicit operator bool() const;
bool has_value() const;
// utility functions
void swap(Optional & o);
void reset();
private:
int * data {};
};
class no_value_error: public std::runtime_error
{
using std::runtime_error::runtime_error;
};
#include "optional.h"
#include "catch.hpp"
TEST_CASE( "empty" )
{
Optional o;
REQUIRE_FALSE(o.has_value());
REQUIRE_THROWS_AS(o.value(), no_value_error);
SECTION ("reassign")
{
o = 5;
CHECK(o.value() == 5);
}
}
TEST_CASE( "has value" )
{
Optional o{2};
CHECK(o.has_value());
CHECK(*o == 2);
SECTION ("reassign")
{
o = 5;
CHECK(o.value() == 5);
}
SECTION("no_value")
{
o = no_value;
CHECK_FALSE(o.has_value());
}
}
Optional get_value(bool should_return)
{
if (should_return)
{
return 3;
}
return no_value;
}
TEST_CASE("create in function")
{
CHECK(get_value(true).has_value());
CHECK_FALSE(get_value(false).has_value());
}
# Template version
När en template-klass kompileras (eller rättare sett när kompilatorn instansierar mallen) behövs implementation. Därför inkluderar man vanligtvis implementationsfilen i slutet av header-filen. Ofta byter man filnamn på implementationsfilen så man inte råkar kompilerar den.
#pragma once
#include <memory>
#include <stdexcept>
struct no_value_t {} const no_value{};
template <typename T>
class Optional
{
public:
Optional() = default;
Optional(Optional const & o);
Optional & operator=(Optional const & o) &;
Optional(Optional &&) = default;
// initialize from underlying type
Optional(T i);
Optional & operator=(T i) &;
// Set to no_value
Optional(no_value_t) noexcept;
Optional & operator=(no_value_t) noexcept;
// accessors. value throws when unset, dereferencing unset value is undefined
T & value();
T const & value() const;
T & operator*() noexcept;
T const & operator*() const noexcept;
// checker
explicit operator bool() const;
bool has_value() const;
// utility functions
void swap(Optional & o);
void reset();
private:
std::unique_ptr<T> data {};
};
class no_value_error: public std::runtime_error
{
using std::runtime_error::runtime_error;
};
#include "optional.tcc"
#include "optional.h"
#include <utility>
template<typename T>
Optional<T>::Optional(T i) : data { std::make_unique<T>( i )} {}
template<typename T>
Optional<T>::Optional(Optional<T> const& o)
{
if (o.has_value())
{
data = std::make_unique<T>( *o );
}
}
template<typename T>
Optional<T>& Optional<T>::operator=(Optional const& o)&
{
Optional{ o }.swap(*this);
return *this;
}
template<typename T>
Optional<T>& Optional<T>::operator=(T i)&
{
if (!has_value())
{
data = std::make_unique<T>();
}
*data = i;
return *this;
}
template<typename T>
Optional<T>::Optional(no_value_t) noexcept: data {} {}
template<typename T>
Optional<T>& Optional<T>::operator=(no_value_t) noexcept
{
reset();
return *this;
}
template<typename T>
T& Optional<T>::value()
{
if (!has_value())
{
throw no_value_error{ "No value!" };
}
return *data;
}
template<typename T>
T const& Optional<T>::value() const
{
if (!has_value())
{
throw no_value_error{ "No value!" };
}
return *data;
}
template<typename T>
Optional<T>::operator bool() const
{
return has_value();
}
template<typename T>
bool Optional<T>::has_value() const
{
return data != nullptr;
}
template<typename T>
T const& Optional<T>::operator*() const noexcept
{
return *data;
}
template<typename T>
T& Optional<T>::operator*() noexcept
{
return *data;
}
template<typename T>
void Optional<T>::swap(Optional& o)
{
using std::swap;
swap(data, o.data);
}
template<typename T>
void Optional<T>::reset()
{
data.reset();
}
#include "optional.h"
#include "catch.hpp"
TEST_CASE( "empty" )
{
Optional<int> o;
REQUIRE_FALSE(o.has_value());
REQUIRE_THROWS_AS(o.value(), no_value_error);
SECTION ("reassign")
{
o = 5;
CHECK(o.value() == 5);
}
}
TEST_CASE( "has value" )
{
Optional<int> o{2};
CHECK(o.has_value());
CHECK(*o == 2);
SECTION ("reassign")
{
o = 5;
CHECK(o.value() == 5);
}
SECTION("no_value")
{
o = no_value;
CHECK_FALSE(o.has_value());
}
}
Optional<int> get_value(bool should_return)
{
if (should_return)
{
return 3;
}
return no_value;
}
TEST_CASE("create in function")
{
CHECK(get_value(true).has_value());
CHECK_FALSE(get_value(false).has_value());
}
TEST_CASE( "string" )
{
Optional<std::string> o{"hello"};
CHECK(o.has_value());
CHECK(*o == "hello");
SECTION ("reassign")
{
o = "nu";
CHECK(o.value() == "nu");
}
SECTION("no_value")
{
o = no_value;
CHECK_FALSE(o.has_value());
}
}
#include "optional.h"
#include <utility>
#include <memory>
Optional::Optional(int i)
: data{new int{i}}
{}
Optional::Optional(Optional const & o)
{
if (o.has_value())
{
data = std::make_unique<int>(*o);
}
}
Optional & Optional::operator=(Optional const & o)&
{
Optional{o}.swap(*this);
return *this;
}
Optional & Optional::operator=(int i)&
{
if ( !has_value() )
{
data = std::make_unique<int>();
}
*data = i;
return *this;
}
Optional::Optional(no_value_t) noexcept: data{} {}
Optional& Optional::operator=(no_value_t) noexcept
{
reset();
return *this;
}
int & Optional::value()
{
if ( !has_value() )
throw no_value_error{"No value!"};
return *data;
}
int const & Optional::value() const
{
if ( !has_value() )
throw no_value_error{"No value!"};
return *data;
}
Optional::operator bool() const
{
return has_value();
}
bool Optional::has_value() const
{
return data != nullptr;
}
int const & Optional::operator*() const noexcept
{
return *data;
}
int & Optional::operator*() noexcept
{
return *data;
}
void Optional::swap(Optional & o)
{
using std::swap;
swap(data, o.data);
}
void Optional::reset()
{
data.reset();
}
#pragma once
#include <stdexcept>
#include <memory>
struct no_value_t {} inline const no_value{};
class Optional
{
public:
Optional() = default;
Optional(Optional const & o);
Optional & operator=(Optional const & o) &;
// initialize from underlying type
Optional(int i);
Optional & operator=(int i) &;
// Set to no_value
Optional(no_value_t) noexcept;
Optional & operator=(no_value_t) noexcept;
// accessors. value throws when unset, dereferencing unset value is undefined
int & value();
int const & value() const;
int & operator*() noexcept;
int const & operator*() const noexcept;
// checker
explicit operator bool() const;
bool has_value() const;
// utility functions
void swap(Optional & o);
void reset();
private:
std::unique_ptr<int> data {};
};
class no_value_error: public std::runtime_error
{
using std::runtime_error::runtime_error;
};
#include "optional.h"
#include "catch.hpp"
TEST_CASE( "empty" )
{
Optional o;
REQUIRE_FALSE(o.has_value());
REQUIRE_THROWS_AS(o.value(), no_value_error);
SECTION ("reassign")
{
o = 5;
CHECK(o.value() == 5);
}
}
TEST_CASE( "has value" )
{
Optional o{2};
CHECK(o.has_value());
CHECK(*o == 2);
SECTION ("reassign")
{
o = 5;
CHECK(o.value() == 5);
}
SECTION("no_value")
{
o = no_value;
CHECK_FALSE(o.has_value());
}
}
Optional get_value(bool should_return)
{
if (should_return)
{
return 3;
}
return no_value;
}
TEST_CASE("create in function")
{
CHECK(get_value(true).has_value());
CHECK_FALSE(get_value(false).has_value());
}
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
int main(int argc, char* argv[])
{
return Catch::Session{}.run(argc, argv);
}
ptr.cc 0 → 100644
#include <memory>
using namespace std;
// requires the user to explicitly move the resouce at call site.
void take_resource(unique_ptr<int> p) {}
int main()
{
unique_ptr<int> p1;
// make_unique takes the arguments required by the constructor of the stored type
p1 = make_unique<int>(5);
p1 = make_unique<int>(6);
unique_ptr<int> p2 { new int{2} };
p1 = move(p2);
// get access to (but not ownership of) resource
int * ptr = p1.get();
// Here both p1 and p3 beleives that they own the pointer... BAD!
//unique_ptr<int> p3 { p1.get() };
// Instead we move construct.
unique_ptr<int> p3 { move(p1) };
take_resource(move(p3));
}
push.cc 0 → 100644
// We create a function that calls push_back on a given container
#include <vector>
#include <string>
using namespace std;
// we want val to be of the type of the values that are stored
// in the container. All STL containers have a member type called
// value_type. Container::value_type is a dependent name (could be
// many things, not only a type) and the compiler isn't (at the moment) allowed
// to assume that it is a type -> we have to explicitly state that
// it is the name of a type (typename).
// using class or typename in the template parameter declaration doesn't matter
template <class Container>
void push(Container & v, typename Container::value_type val)
{
v.push_back(val);
}
int main()
{
vector<int> vals;
push(vals, 3);
vector<string> s;
push(s, "hej");
// doesn't compile...
//push(vals, "hejsan");
}
sum.cc 0 → 100644
#include <iostream>
using namespace std;
// auto return type, let the compiler figure out the correct type from
// the return statement.
template <typename T, typename U>
auto sum(T a, U b)
{
return a+b;
}
int main()
{
cout << sum(1,2.3) << endl;
cout << sum(1.3,2.8) << endl;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment