forked from furkankirac/cs409-2023-24-spring
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a29f621
commit e6efcd5
Showing
4 changed files
with
283 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// parameter type binding exercises | ||
|
||
#include <iostream> | ||
|
||
template<typename> struct TypeDisplayer; | ||
|
||
struct Widget { }; | ||
|
||
// (1) function with l-value ref | ||
void f(Widget&) { std::cout << "1\n"; } | ||
|
||
// (2) function with l-value ref-to-const | ||
void f(const Widget&) { std::cout << "2\n"; } | ||
|
||
// (3) function with r-value ref | ||
void f(Widget&&) { std::cout << "3\n"; } | ||
|
||
// (4) function with r-value ref-to-const | ||
void f(const Widget&&) { std::cout << "4\n"; } | ||
|
||
// (5) function template with forwarding ref | ||
template<typename T> | ||
void f(T&&) { std::cout << "5\n"; } | ||
|
||
// (6) function template with r-value ref-to-const | ||
template<typename T> | ||
void f(const T&&) { std::cout << "6\n"; } | ||
|
||
Widget getWidget() { Widget w; return w; } | ||
|
||
const Widget getConstWidget() { const Widget w; return w; } | ||
|
||
int main(int argc, char* argv[]) | ||
{ | ||
// what is the preference order of above functions for below questions? | ||
Widget w1{}; // auto w1 = Widget{}; | ||
f(w1); | ||
|
||
const Widget w2{}; | ||
f(w2); | ||
|
||
f(getWidget()); | ||
|
||
f(getConstWidget()); | ||
|
||
return 0; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
#include <iostream> | ||
//#include <string> | ||
|
||
// move semantics pitfalls | ||
|
||
// pitfall #1: | ||
// T&& in deduced context is a forwarding reference | ||
// it can match to both lvalues and rvalues. | ||
// using std::move is an unconditional cast to rvalue. | ||
// this is wrong if constructor of A is used with an lvalue in call site. | ||
namespace PF1 | ||
{ | ||
struct B { }; | ||
struct A | ||
{ | ||
B b_; | ||
|
||
template<typename T> | ||
A(T&& t) : b_{std::move(t)} | ||
{ } | ||
}; | ||
} | ||
|
||
// pitfall #2: | ||
// T&& here is not a forwarding reference! | ||
// because T's deduction is done when struct A is instantiated. | ||
// A's constructor is not itself templated. Hence, T&& means rvalue reference | ||
// in an rvalue context, using std::forward is wrong | ||
// std::forward is a CONDITIONAL cast to rvalue. However, we are sure that | ||
// the context is already rvalue. std::move would be correct. | ||
namespace PF2 | ||
{ | ||
struct B { }; | ||
template<typename T> | ||
struct A | ||
{ | ||
B b_; | ||
|
||
A(T&& t) : b_{std::forward<T>(t)} | ||
{ } | ||
}; | ||
} | ||
|
||
// pitfall #3: | ||
// T&& is a forwarding reference. | ||
// however, if A's contructor is called with an rvalue | ||
// std::forward will cast t to &&. | ||
// unfortunately there is only one 't' instance. | ||
// first move constructor using 't' will steal its internals. | ||
// 't' will be useless for its second usage. | ||
// will cause major bug that cannot be easily detected | ||
namespace PF3 | ||
{ | ||
struct B { }; | ||
struct C { }; | ||
struct A | ||
{ | ||
B b_; | ||
C c_; | ||
|
||
template<typename T> | ||
A(T&& t) | ||
: b_{std::forward<T>(t)} | ||
, c_{std::forward<T>(t)} | ||
{ | ||
} | ||
}; | ||
} | ||
|
||
|
||
// pitfall #4: | ||
// THIS WAS A TRICK DURING CLASS LECTURE. NOTHING IS WRONG WITH BELOW CODE | ||
// looks like if t1 and t2 are both referencing the same value at the call-site, it is an error. | ||
// but it is not. Because the dangerous thing is stealing/moving from the same value. | ||
// However, two real r-values (temporaries) cannot be the same object at the call site. | ||
// Imagine first r-value is 5, 2nd r-value is 5. There are two different 5s. It's not the same 5. | ||
// So we can move them on their own. No stealing/moving happens on the same l-value. | ||
namespace PF4 | ||
{ | ||
struct B { }; | ||
struct C { }; | ||
struct A | ||
{ | ||
B b_; | ||
C c_; | ||
|
||
template<typename T1, typename T2> | ||
A(T1&& t1, T2&& t2) | ||
: b_{std::forward<T1>(t1)} | ||
, c_{std::forward<T2>(t2)} | ||
{ | ||
} | ||
}; | ||
} | ||
|
||
template<typename ...> | ||
struct TypeDisplayer; | ||
|
||
#include <type_traits> | ||
|
||
// pitfall #5: | ||
// std::is_integral<T>::value waits for a T that does not contain & or * | ||
// However a forwarding reference may deduce T with a & inside. | ||
// For instance, T can be deduced as float& | ||
// passing float& to is_integral such as std::is_integral<float&> is wrong | ||
// a reference is a pointer in its implementation | ||
// pointers are memory addresses that are actually integral values | ||
// in below code, you should remove a potential reference yourself and use that | ||
// for instance use new type K in below code | ||
template<typename T> | ||
void foo(T&&) | ||
{ | ||
// using K = std::remove_reference_t<T>; | ||
|
||
// TypeDisplayer<K> a; | ||
if constexpr(std::is_integral<T>::value) // use K here, instead of T | ||
{ | ||
// deal with integral types: char, short, int, long, ... | ||
} | ||
else | ||
{ | ||
// deal with non-integral types | ||
} | ||
} | ||
|
||
int main(int argc, char* argv[]) | ||
{ | ||
int a = 5; | ||
foo(a); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#include <iostream> | ||
#include <vector> | ||
#include <string> | ||
#include <cstring> | ||
|
||
using namespace std; | ||
|
||
struct BigObject { | ||
string s; | ||
vector<char> data; | ||
|
||
// BigObject(const char* s) { | ||
|
||
// } | ||
|
||
BigObject() = default; | ||
|
||
template<typename T> | ||
BigObject(T&& s, const char* p) | ||
: s(std::forward<T>(s)) | ||
, data(strlen(p) + 1) | ||
{ | ||
for(int i=0; i<data.size(); i++) | ||
data[i] = p[i]; | ||
// if constexpr(std::is_same_v<T, string>) { | ||
|
||
// } | ||
} | ||
|
||
template<typename T> | ||
BigObject(T&& other) | ||
: s(std::forward<T>(other.s)) | ||
, data(std::forward<T>(other.data)) | ||
{ | ||
// ... | ||
// ... | ||
// ... | ||
// ... | ||
// ... | ||
// ... | ||
// ... | ||
// ... | ||
} | ||
|
||
// BigObject(const BigObject& other) : s(other.s), data(other.data) | ||
// { | ||
// // ... | ||
// // ... | ||
// // ... | ||
// // ... | ||
// // ... | ||
// // ... | ||
// } | ||
// BigObject(BigObject&& other) : s(std::move(other.s)), data(std::move(other.data)) { | ||
// // ... | ||
// // ... | ||
// // ... | ||
// // ... | ||
// // ... | ||
// // ... | ||
// // ... | ||
// } | ||
|
||
// BigObject(const string& s) : s(s) { } | ||
// BigObject(string&& s) : s(std::move(s)) { } | ||
}; | ||
|
||
auto foo(auto&& func) { | ||
char data[] = {'h', 'i', ' ', 't', 'h', 'e', 'r', 'e', '!', 0}; | ||
auto bo = BigObject{"abc", data}; | ||
func(); | ||
return bo; | ||
} | ||
|
||
|
||
// struct FFFF { | ||
// BigObject k; | ||
// // void* _vtable; // 8 bytes | ||
|
||
// void operator() () { | ||
// cout << "I am a dying lambda" << endl; | ||
// } | ||
|
||
// // virtual void another() { } | ||
// // virtual void another2() { } | ||
// }; | ||
|
||
int main(int argc, char* argv[]) | ||
{ | ||
// auto f = FFFF{}; | ||
// auto g = FFFF{}; | ||
// cout << sizeof(f) << endl; | ||
BigObject k; | ||
auto f = []() { cout << "I am a dying lambda" << endl; }; | ||
BigObject bo = foo(f); // copy ctor? move ctor? | ||
|
||
BigObject bo2 = std::move(bo); | ||
|
||
return 0; | ||
} |