Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <cstring>
- #include <vector>
- template<typename T>
- class Array {
- private:
- std::vector<T> data_;
- public:
- explicit Array(size_t n, T val = T()): data_(n, val) {}
- /* конструктор, принимающий список инициализации */
- // Array(std::initializer_list<T> l): data_(l) {}
- };
- /* пример С-структуры */
- struct Point {
- int x, y;
- };
- /* посмотрим на конструкторы чего-то похожего на std::string
- * нет 0-ого символа в конце, хотим просто взглянуть на конструкторы */
- class String {
- public:
- String() {
- data_ = new char[1];
- data_[0] = '\0';
- }
- String(const char *s) {
- size_t len = strlen(s);
- data_ = new char[len + 1];
- memcpy(data_, s, len + 1);
- }
- /* конструктор копирования */
- String(const String& s) {
- std::cout << "copy ctor of String\n";
- size_t len = s.size();
- data_ = new char[len + 1];
- memcpy(data_, s.data_, len + 1);
- }
- /* конструктор перемещения
- * поскольку s ссылается на rvalue, может спокойно
- * испортить объект, он все равно скоро будет уничтожен */
- String(String&& s): data_(s.data_) {
- std::cout << "move ctor of String\n";
- s.data_ = nullptr;
- }
- /* принимаем по значению, чтобы воспользоваться конструкторами
- * если передавалось lvalue, то s будет сконструировано
- * с помощью конструктора копирования, поэтому тут s - копия, никак не свяязанная
- * с оригинальным объектом, можно делать с ней что угодно.
- * Если передавалось rvalue, будет вызван конструктор перемещения,
- * т.е. s.data_ по сути указывает на бывшую память временного объекта, поэтому сам s снова
- * больше не нужен */
- String& operator=(String s) {
- std::cout << "operator = of String\n";
- delete[] data_;
- data_ = s.data_;
- s.data_ = nullptr;
- return *this;
- }
- ~String() {
- if (data_ != nullptr)
- delete[] data_;
- }
- size_t size() const {
- return strlen(data_);
- }
- private:
- char *data_;
- };
- void anotherFunc(String&& s) {
- std::cout << "got rvalue in anotherFunc\n";
- }
- void anotherFunc(const String& s) {
- std::cout << "got lvalue in anotherFunc\n";
- }
- /* T&& не является rvalue-ссылкой, можно это называть универсальной ссылкой
- * (см. способы вызова)
- * аргументы функций - ВСЕГДА lvalue (можем взять адрес)
- * хотим получить rvalue, если в месте вызова было передано rvalue
- * и lvalue в противном случае. Это и делает std::forward.
- * Это позволяет осуществлять perfect forwarding - передачу аргументов дальше
- * ровно в том виде, в котором они были переданы */
- template<typename T>
- void someFunc(T&& arg) {
- anotherFunc(std::forward<T>(arg));
- }
- class StringWrapper {
- public:
- StringWrapper(const String& s): str_(s) {}
- StringWrapper(const StringWrapper& s): str_(s.str_) {
- std::cout << "copy ctor of StringWrapper\n";
- }
- /* как уже говорилось, аргументы всегда являются lvalue
- * но мы тут имеем ссылку на rvalue, поэтому хотим сделать
- * s.str_ rvalue - это и делает std::move */
- StringWrapper(StringWrapper&& s): str_(std::move(s.str_)) { // вызов конструктора перемещения
- std::cout << "move ctor of StringWrapper\n";
- }
- StringWrapper& operator=(StringWrapper s) {
- std::cout << "operator = of StringWrapper\n";
- str_ = std::move(s.str_);
- return *this;
- }
- private:
- // StringWrapper(const StringWrapper& s) = delete; // пример удаления конструктора копирования
- String str_;
- };
- String returnSomeString() {
- return "123";
- }
- /* вычисления на этапе компиляции
- * замена страшным решениям с помощью шаблонов
- * constexpr функции должны содержать только один return
- * в C++14 требование ослабили */
- constexpr int pow(int a, int b) {
- return b == 0 ? 1 : a * pow(a, b - 1);
- }
- int main() {
- Point p = {1, 2}; // инициализация в стиле С простых структур
- /* теперь можно использовать фигурные скобки и для вызова обычных конструкторов
- * внутри таких конструкторов запрещены небезопасные приведения типов
- * например size_t в int, long long в double и т.д. */
- Array<int> a{5u, 3};
- std::vector<int> v = {1, 2, 3}; // вызов конструктора от std::initializer_list
- /* конструктор от списка инициализации всегда имеет приоритет при вызове через {}
- * поэтому здесь создается вектор из 1-ого элемента 7 */
- std::vector<int> v2{7};
- String s("abc");
- StringWrapper w(s);
- StringWrapper w1(w); // конструктор копирования
- StringWrapper w2 = std::move(w); // делаем w rvalue, вызывается конструктор перемещения
- StringWrapper w3(s);
- w1 = w3;
- w2 = std::move(w3);
- /* вызов функции, принимающей универсальную ссылку */
- someFunc(s); // вызов с lvalue, T = string& , type of arg = string&
- someFunc(returnSomeString()); // вызов с rvalue, T = string, type of arg = string&&
- constexpr int n = 7;
- int some_array[pow(3, n)]; // вычисляется на этапе компиляции
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement