/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby,
C#, VB, Perl, Swift, Prolog, Javascript, Pascal, HTML, CSS, JS
Code, Compile, Run and Debug online from anywhere in world.
GS
14 Sept. 2020
*******************************************************************************/
// // =============================================================================
// // **Non-copyable class Example 1:**
// // =============================================================================
// #include <stdio.h>
// class NonCopyable1
// {
// public:
// int i = 5;
// // Delete the assignment operator to make this class non-copyable
// NonCopyable1& operator=(const NonCopyable1& other) = delete;
// };
// int main()
// {
// printf("Hello World\n");
// NonCopyable1 nc1;
// NonCopyable1 nc2;
// nc2 = nc1; // copy assignment; compile-time error!
// NonCopyable1 nc3 = nc1; // copy constructor; works fine!
// return 0;
// }
// =============================================================================
// **Non-copyable class Example 2:**
// =============================================================================
// #include <stdio.h>
// class NonCopyable1
// {
// public:
// const int i = 5; // classes with `const` members are non-copyable by default
// };
// int main()
// {
// // printf("Hello World\n");
// NonCopyable1 nc1;
// NonCopyable1 nc2;
// nc2 = nc1; // copy assignment; compile-time error!
// NonCopyable1 nc3 = nc1; // copy constructor; works fine!
// return 0;
// }
// =============================================================================
// **So, if a class is non-copyable, you can NOT do the following to get a copy of it as an output!**
// =============================================================================
// #include <cstring> // for `memcpy()`
// #include <type_traits> // for `std::is_trivially_copyable<>()`
// #include <functional>
// #include <stdio.h>
// class NonCopyable1
// {
// public:
// const int i; // classes with `const` members are non-copyable by default
// // Constructor to custom-initialize `i`
// NonCopyable1(int val = 5) : i(val)
// {
// // nothing else to do
// }
// NonCopyable1& operator=(const NonCopyable1& other);
// };
// // Some class which (perhaps asynchronously) processes data. You attach a
// // callback, which gets called later.
// // - Also, this may be a shared library over which you have no or little
// // control, so you cannot easily change the prototype of the callable/callback
// // function.
// class ProcessData
// {
// public:
// void attachCallback(std::function<void(void)> callable)
// {
// callback_ = callable;
// }
// void callCallback()
// {
// callback_();
// }
// private:
// std::function<void(void)> callback_;
// };
// int main()
// {
// printf("Hello World\n");
// NonCopyable1 outputData; // we need to receive back data through this object
// printf("outputData.i (before) = %i\n", outputData.i); // is 5
// ProcessData processData;
// // // Attach a lambda function as a callback, capturing `outputData` by
// // // reference so we can receive back the data from inside the callback via
// // // this object even though the callable prototype returns `void` (is a
// // // `void(void)` callable/function).
// // processData.attachCallback([&outputData]()
// // {
// // int someRandomData = 997;
// // NonCopyable1 data(someRandomData);
// // // NOT ALLOWED SINCE COPY OPERATOR (Assignment operator) WAS
// // // AUTO-DELETED since the class has a `const` data member!
// // // outputData = data;
// // static_assert(std::is_trivially_copyable<NonCopyable1>::value, "NonCopyable1 must "
// // "be a trivially-copyable type in order to guarantee that `memcpy()` is safe "
// // "to use on it.");
// // outputData.~NonCopyable1(); // manually call destructor before overwriting this object
// // memcpy(&outputData, &data, sizeof(data));
// // // // copy-construct `data` right into the address at `&outputData`, using placement new syntax
// // // new(&outputData) NonCopyable1(data);
// // // // new(&outputData) NonCopyable1(400);
// // });
// processData.attachCallback([&outputData]()
// {
// int someRandomData = 999;
// NonCopyable1 data(someRandomData);
// static_assert(std::is_trivially_copyable<NonCopyable1>::value, "NonCopyable1 must "
// "be a trivially-copyable type in order to guarantee that `memcpy()` is safe "
// "to use on it.");
// outputData.~NonCopyable1(); // manually call destructor before overwriting this object
// memcpy(&outputData, &data, sizeof(data));
// });
// processData.callCallback();
// // verify we get 999 here, NOT 5!
// printf("outputData.i (after) = %i\n", outputData.i);
// return 0;
// }
// =============================================================================
// std::optional<> example!
// =============================================================================
#include <cstdio>
#include <functional>
#include <optional> // std::optional
class NonCopyable1
{
public:
const int i; // classes with `const` members are non-copyable by default
// Constructor to custom-initialize `i`
NonCopyable1(int val = 5) : i(val)
{
// nothing else to do
}
// Make non-trivially-copyable by defining a custom copy/assignment
// operator:
// Custom copy/assignment operator definition:
NonCopyable1& operator=(const NonCopyable1& other)
{
// Check for, **and don't allow**, self assignment!
// ie: only copy the contents from the other object
// to this object if it is not the same object (ie: if it is not
// self-assignment)!
if(this != &other)
{
// copy all non-const members manually here, if the class had any; ex:
// j = other.j;
// k = other.k;
// etc.
// Do deep copy of data via any member **pointers**, if such members exist
}
// the assignment function (`operator=()`) expects you to return the
// contents of your own object (the left side), passed by reference, so
// that constructs such as `test1 = test2 = test3;` are valid!
// See this reference, from Stanford, p11, here!:
// http://web.stanford.edu/class/archive/cs/cs106b/cs106b.1084/cs106l/handouts/170_Copy_Constructor_Assignment_Operator.pdf
// MyClass one, two, three;
// three = two = one;
return *this;
}
};
// Some class which (perhaps asynchronously) processes data. You attach a
// callback, which gets called later.
// - Also, this may be a shared library over which you have no or little
// control, so you cannot easily change the prototype of the callable/callback
// function.
class ProcessData
{
public:
void attachCallback(std::function<void(void)> callable)
{
callback_ = callable;
}
void callCallback()
{
callback_();
}
private:
std::function<void(void)> callback_;
};
int main()
{
printf("Hello World\n");
std::optional<NonCopyable1> outputData = std::nullopt;
ProcessData processData;
// Attach a lambda function as a callback, capturing `outputData` by
// reference so we can receive back the data from inside the callback via
// this object even though the callable prototype returns `void` (is a
// `void(void)` callable/function).
processData.attachCallback([&outputData]()
{
int someRandomData = 999;
NonCopyable1 data(someRandomData);
// emplace `data` right into the `outputData` object
outputData.emplace(data);
});
processData.callCallback();
// verify we get 999 here!
if (outputData.has_value())
{
printf("(*outputData).i (after) = %i\n", (*outputData).i);
// OR
printf("outputData.value().i (after) = %i\n", outputData.value().i);
}
else
{
printf("outputData.has_value() is false!");
}
return 0;
}