My goal is to prevent initializing FibonacciMemoization
class except with the FibonacciMemoization::getInstance()
function.
Goal:
- [ ] prevent initializing with
FibonacciMemoization* object1 = new FibonacciMemoization();
- [ ] prevent initializing with
FibonacciMemoization object1;
The code
// https://en.cppreference.com/w/cpp/memory/weak_ptr
// https://refactoring.guru/design-patterns/singleton/cpp/example#example-1
#ifndef FIBONACCI_MEMOIZATION_HPP
#define FIBONACCI_MEMOIZATION_HPP
#include <unordered_map>
#include <mutex>
class FibonacciMemoization {
public:
static std::shared_ptr<FibonacciMemoization> getInstance();
/**
* Singleton should not be cloneable.
*
* auto object1 = FibonacciMemoization(); // no matchng constructor for initialization of 'FibonacciMemoization'
* This line creates an instance of the `FibonacciMemoization` class using its constructor and then assigns this newly created instance to the `object1`.
* This involves both construction and assignment.
*
* FibonacciMemoization object1;
* FibonacciMemoization object2 = object1; // function "FibonacciMemoization::FibonacciMemoization(FibonacciMemoization &other)" cannot be referenced -- it is a deleted function
* This line does not create a new instance of the `FibonacciMemoization` class.
* Instead, it creates a new variable `object2` and attempts to initialize it by copying the value of `object1`.
* Without deleting the copy constructor `object2` would be a separate instance that could behave independently of `object1`.
*
* auto object1 = FibonacciMemoization::getInstance();
* FibonacciMemoization object2 = *object1; // function "FibonacciMemoization::FibonacciMemoization(FibonacciMemoization &other)" cannot be referenced -- it is a deleted function
* `object2` would be a separate instance that could behave independently of `object1`.
*/
FibonacciMemoization(FibonacciMemoization &other) = delete;
/**
* Singleton should not be assignable.
* auto object1 = FibonacciMemoization();
* auto object2 = FibonacciMemoization();
* object2 = object1; // function "FibonacciMemoization::operator=(const FibonacciMemoization &)" cannot be referenced - it is a deleted function
*/
void operator=(const FibonacciMemoization &) = delete;
~FibonacciMemoization();
unsigned long calculate(unsigned n);
private:
static std::weak_ptr<FibonacciMemoization> instance;
static std::mutex mutex;
FibonacciMemoization();
int id;
std::unordered_map<unsigned, unsigned> cache;
unsigned long fibonacci(unsigned n);
};
#endif
#include "fibonacciMemoization.hpp"
#include <iostream>
FibonacciMemoization::FibonacciMemoization() {
srand(time(0));
id = rand();
std::cout << typeid(*this).name() << " " << __func__ << " " << id << "\n\n";
}
FibonacciMemoization::~FibonacciMemoization() {
std::cout << typeid(*this).name() << " " << __func__ << " " << id << "\n\n";
}
std::weak_ptr<FibonacciMemoization> FibonacciMemoization::instance;
std::mutex FibonacciMemoization::mutex;
std::shared_ptr<FibonacciMemoization> FibonacciMemoization::getInstance() {
std::shared_ptr<FibonacciMemoization> sp;
std::lock_guard<std::mutex> lock(mutex);
if (instance.expired()) {
sp = std::make_shared<FibonacciMemoization>();
instance = sp;
}
return instance.lock();
}
unsigned long FibonacciMemoization::calculate(unsigned n) {
cache.clear();
return fibonacci(n);
}
unsigned long FibonacciMemoization::fibonacci(unsigned n) {
if (n < 2)
return n;
if (cache.find(n) != cache.end())
return cache[n];
unsigned long fib_n = fibonacci(n - 1) + fibonacci(n - 2);
cache[n] = fib_n;
return fib_n;
}
The usage code
#include <chrono>
#include <iostream>
#include "fibonacci.cpp"
#include "fibonacciMemoization.hpp"
void fibonacciExample() {
const auto start = std::chrono::steady_clock::now();
const auto fb = fibonacci(42);
const auto end = std::chrono::steady_clock::now();
const std::chrono::duration<double> elapsed_seconds = end - start;
std::cout << "fibonacci example\n";
std::cout << "f(42) = " << fb << '\n' << "elapsed time: ";
std::cout << elapsed_seconds.count() << "s\n\n"; // Before C++20
// std::cout << elapsed_seconds << "\n\n"; // C++20: operator<< chrono::duration
}
void fibonacciMemoizationExample() {
const auto start = std::chrono::steady_clock::now();
// example A pf the unexpected usage.
// FibonacciMemoization object;
// const auto fb = object.calculate(42);
// example B of the unexpected usage.
// auto object = new FibonacciMemoization();
// const auto fb = object->calculate(42);
// the expected usage
auto object = FibonacciMemoization::getInstance();
const auto fb = object->calculate(42);
const auto end = std::chrono::steady_clock::now();
const std::chrono::duration<double> elapsed_seconds = end - start;
std::cout << "fibonacci memoization example\n";
std::cout << "f(42) = " << fb << '\n' << "elapsed time: ";
std::cout << elapsed_seconds.count() << "s\n\n";
// example B of the unexpected usage.
// need to explicitly call destructor after use due to use of the `new` keyword.
// delete object;
}
The problem is that std::make_shared<FIbonacciMemoization>()
require public constructor and destructor.
What I've tried:
- set
FibonacciMemoization
constructor to private.
The expected result: the compiler and run do not generate error.
The actual result: the compiler generate error.
g++ -std=c++11 main.cpp fibonacciMemoization.cpp -o main && ./main
In file included from main.cpp:1:
In file included from ./menu.cpp:3:
./fibonacciexample.cpp:23:26: error: calling a private constructor of class 'FibonacciMemoization'
FibonacciMemoization object;
^
./fibonacciMemoization.hpp:48:5: note: declared private here
FibonacciMemoization();
^
1 error generated.
In file included from fibonacciMemoization.cpp:1:
In file included from ./fibonacciMemoization.hpp:7:
In file included from /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/unordered_map:523:
In file included from /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__hash_table:25:
In file included from /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/memory:860:
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/shared_ptr.h:294:37: error: calling a private constructor of class 'FibonacciMemoization'
::new ((void*)__get_elem()) _Tp(_VSTD::forward<_Args>(__args)...);
^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/shared_ptr.h:953:55: note: in instantiation of function template specialization 'std::__shared_ptr_emplace<FibonacciMemoization, std::allocator<FibonacciMemoization>>::__shared_ptr_emplace<>' requested here
::new ((void*)_VSTD::addressof(*__guard.__get())) _ControlBlock(__a, _VSTD::forward<_Args>(__args)...);
^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/shared_ptr.h:962:19: note: in instantiation of function template specialization 'std::allocate_shared<FibonacciMemoization, std::allocator<FibonacciMemoization>, void>' requested here
return _VSTD::allocate_shared<_Tp>(allocator<_Tp>(), _VSTD::forward<_Args>(__args)...);
^
fibonacciMemoization.cpp:22:19: note: in instantiation of function template specialization 'std::make_shared<FibonacciMemoization, void>' requested here
sp = std::make_shared<FibonacciMemoization>();
^
./fibonacciMemoization.hpp:48:5: note: declared private here
FibonacciMemoization();
^
1 error generated.
Aucun commentaire:
Enregistrer un commentaire