1. C++ / Говнокод #27326

    0

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    89. 89
    90. 90
    91. 91
    92. 92
    93. 93
    94. 94
    95. 95
    96. 96
    97. 97
    98. 98
    99. 99
    class MyString
    {
    public:
    	MyString(const char* str)
    	{
    		symbol = strlen(str);
    		this->str = new char[symbol + 1];
    		for (int i = 0; i < symbol; i++)
    		{
    			this->str[i] = str[i];
    		}
    		this->str[symbol] = '\0';
    	}
    	int Size()
    	{
    		return symbol;
    	}
    	MyString()
    	{
    		str = nullptr;
    		symbol = 0;
    	}
    	~MyString()
    	{
    		delete[] str;
    	}
    	MyString(const MyString& objct)
    	{
    		symbol = strlen(objct.str);
    		this->str = new char[symbol + 1];
    		for (int i = 0; i < symbol; i++)
    		{
    			this->str[i] = objct.str[i];
    		}
    		this->str[symbol] = '\0';
    	}
    	MyString operator ()(const char* objct)
    	{
    		if (this->str != nullptr)
    		{
    			delete[] this->str;
    		}
    		symbol = strlen(objct);
    		this->str = new char[symbol + 1];
    		for (int i = 0; i < symbol; i++)
    		{
    			this->str[i] = objct[i];
    		}
    		this->str[symbol] = '\0';
    		return *this;
    	}
    	MyString& operator =(MyString& objct)
    	{
    		if (this->str != nullptr)
    		{
    			delete[] str;
    		}
    		symbol = strlen(objct.str);
    		this->str = new char[symbol + 1];
    		for (int i = 0; i < symbol; i++)
    		{
    			this->str[i] = objct.str[i];
    		}
    		this->str[symbol] = '\0';
    		return *this;
    	}
    	MyString operator +(MyString& objct)//конкатенация строк
    	{
    		MyString NEWString;
    		symbol = strlen(this->str);
    		Ssymbol = strlen(objct.str);
    		NEWString.str = new char[symbol + Ssymbol + 1];
    		int i = 0;
    		NEWString.symbol = symbol + Ssymbol;
    		for (; i < symbol; i++)
    		{
    			NEWString.str[i] = this->str[i];
    		}
    		for (int j = 0; j < Ssymbol; j++, i++)
    		{
    			NEWString.str[i] = objct.str[j];
    		}
    		NEWString.str[symbol + Ssymbol] = '\0';
    		return NEWString;
    	}
    	//перегруженные операторы........
     int main()
    {
    	MyString asd = "Go";
    	MyString aa = "God";
    	if (asd >= aa)
    	{
    		cout << "Первая переменная больше по символам чем вторая." << endl;
    	}
    	else
    	{
    		cout << "Первая переменная меньше по символам чем вторая." << endl;
    	}
    }

    Свой класс строк. Что можно поправить для лучшей оптимизации?

    Запостил: 1337, 28 Марта 2021

    Комментарии (78) RSS

    • Посмотри функции strcpy или memcpy. Некоторые циклы можно убрать.
      Ответить
    • MyString operator ()(const char* objct)


      А что это за метод? Ты портишь объект и возвращаешь его копию в конце.
      Ответить
    • Зря тут можно кинуть только 100 строк, кинул бы ESP для AC который юзает OpenGL

      З.Ы Я знаю что D3D будет лучше для написания ESP боксов и прочих читов, но просто решил упороться. А так с помощью D3D можно сделать обход OBS и прочих стриминговых программ. Правда для Shadow play такое не сработает, ибо она просто ВСЁ изображение с видяхи записывает, не отдельное окно.
      Ответить
    • > для лучшей оптимизации?
      #include <string>
      using MyString = std::basic_string<char>;

      Оптимизировала (как по строкам, так и по производительности).
      Ответить
      • Вродь как можно не писать инклюд стринг.-.
        Ответить
        • Можно. Но тогда код не скомпилируется.
          Ответить
          • -.-
            У меня всё прекрасно компилируется.
            Ответить
            • Какой компилятор? Какая версия? Какие заголовочные файлы подключены?
              Ответить
              • #include <iostream>
                #include <Windows.h>
                #include "Array.h"
                #pragma warning (disable : 26495)

                Array.h:

                #pragma once
                #include <iostream>
                #pragma warning (disable : 4244)
                #pragma warning (disable : 4083)
                using namespace std;


                Стандарт ISO C++ 17.

                IDE VS 2019
                Ответить
                • Через <iostream> затянуло стринг, поэтому конпелирует. А в общем случае лучше написать.
                  Ответить
                • Открой заголовочный файл iostream.
                  Из него перейди к заголовочному файлу istream.
                  Из него перейди к заголовочному файлу ostream.
                  Из него перейди к заголовочному файлу xlocnum.
                  Из него перейди к заголовочному файлу streambuf.
                  Из него перейди к заголовочному файлу xiosbase.
                  Из него перейди к заголовочному файлу xlocale.
                  Из него перейди к заголовочному файлу xlocinfo.
                  Из него перейди к заголовочному файлу xstring.
                  В нём перейди к строке 2279. Там на твоём компиляторе и будет определение std::basic_string. Тебе повезло.
                  Ответить
    • Для начала стоит перестать течь в операторе присваивания при определённых случаях.
      Не течь а портить строку, простите. И вызывать UB.

      И сделать аргумент константным тоже неплохо было бы.
      Ответить
    • Ну давай разберём по частям всё тобою написанное.

      > class MyString
      Что это за класс? Зачем он нужен? Почему его нельзя заменить std::string? Почему его нельзя заменить классом-композитом с std::string? Почему его нельзя заменить классом-наследником std::string?
      Что делать, когда понадобится хранить строки из wchar_t?

      > this->str
      private:
          std::unique_ptr<char[]> str{};

      В C++ использовать сырые указатели для управления памятью — харам, запрет, анафема.

      > this->str = new char[symbol + 1];
      str = std::make_unique<char[]>(symbol + 1);



      > for (int i = 0; i < symbol; i++)
      std::memcpy

      > MyString(const char* str)
      Не хватает (если уж мы говорим про оптимизацию) ещё пары перегрузок:
      MyString(const char *str, size_t size)  // Конструктор с заданной длиной,
                                              // для оптимизации/поддержки строк с \0
      template<size_t TSize>
      MyString(const char (&str)[TSize])  // Конструктор из строкового литерала,
                                          // чтобы не считать длину в рантайме


      > int Size()
      size_t Size() const
      1. Размеры/индексы (за исключением случаев, когда возможны отрицательные числа) — только в size_t.
      2. Все методы, не изменяющие состояние объекта, следует помечать модификатором const,
      чтобы их можно было вызывать на константном объекте.

      > MyString()
      Примитивные инициализаторы членов класса лучше прописывать прямо в их объявлении (см. комментарий к this->str), это гарантирует, что они будут проинициализированы в любом случае.

      > ~MyString()
      После замены str на std::unique_ptr деструктор становится не нужен.

      > MyString(const MyString& objct)
      >> symbol = strlen(objct.str);
      symbol = objct.symbol
      Вычислять длину строки заново каждый раз не требуется — она уже вычислена в конструкторах.
      [Side note: почему objct? Мы же вроде как не в прошлом веке, нам, в отличие от создателей https://linux.die.net/man/2/creat, умещаться в пять символов не требуется]
      Ответить
      • > MyString operator ()(const char* objct)
        [Пропущено]

        > MyString& operator =(MyString& objct)
        const MyString& objct
        Ты не изменяешь второй объект, поэтому нужно принимать константную ссылку.

        > MyString operator +(MyString& objct)
        MyString operator +(const MyString& objct) const
        Оператор + не должен (если быть точным — от него не ожидается этого) изменять состояния ни текущего, ни второго объекта.
        >> symbol = strlen(this->str);
        Э, что? Так в MyString нет члена класса с длиной строки?!

        Наконец, если мы хотим иметь хоть какую-то производительность, то для этого класса совершенно обязательно реализовать move-семантику:
        1. Конструктор MyString(MyString && other);
        2. Оператор присваивания MyString & operator=(MyString && other);
        3. [Опционально] Метод Swap(MyString & other);
        4. [Опционально] Перегрузку std::swap(MyString & a, MyString & b);
        Полное объяснение move-семантики здесь в пару комментариев не уместится, поэтому по этому вопросу направлю в информационно-справочное бюро.
        Ответить
        • Всё, мне можно уходить на пенсию...
          Ответить
          • А ты дерево посадил?
            Ответить
          • Пошли к нам в Coq, с dependent pattern matching поебёмся. Это даже геморнее, чем кресты.
            Ответить
          • Переходи лучше на Си - там всей этой хуйни нет.

            > C++ — довольно таки примитивное, но монстровое поделие, полное исторически сложившихся нелепых нагромождений. Человек, который хорошо в нем ориентируется — это хорошее зубрилко, а не хороший программист.
            Ответить
            • почему зубрилло противопоставляется хорошему программисту?
              Ответить
              • Очевидно, зубрилло это когда ты забиваешь себе мозг всякими языковыми говноньюансами, в которой нет никакогй логики или там математического смысла, когда это просто какое-то кривое ссаное говно, которое кто-то так придумал сделать таким просто потому что так захотелось. (например там типизации Хиндли-Милнера или теории категорий - там есть какое-то логическое математическое обоснвание, а почему в крестах какое-то там блядь наследования дерьма специализацией дерьма работает так а не иначе - это блядь просто так труп страуса придумал)

                А хороший программист не ебется с говноньюансами ублюдски-кривого языка, а решает прикладные задачи, т.е. голова у него забита не говноправилами говноязыка что вот это так наследуется, это так не наследуется, а вот эта говноспециализация хуйни через хуйню вот так работает, а решением прикладной задачи.
                Ответить
                • И получается так, что с таким говнязыками ты решаешь не прикладную задачу, а ебешь себе мозг говноньюансами говнгоязыка, в которых ничего красивого или элегантного нет. И вот это хуево.

                  А в Си говноньюансов на порядок меньше. Именно поэтому я за Си.
                  Ответить
        • свап лучше делать первым. После этого операторы присваивания делаются лениво, поплёвывая в потолок.
          Ответить
        • > Оператор + не должен (если быть точным — от него не ожидается этого) изменять состояния ни текущего, ни второго объекта.

          Это если объект малепусенький, а если он большой и инициализация у него долгая, то лучше, вероятно, перезаписывать его. Но выглядеть будет плохо, да, тогда уж лучше оператор += переопределять.

          Но вряд ли оверхед от создания новых экземпляров будет большой, да и с move-питушней не будет оверхеда от копирования.
          Ответить
          • как мув питущня связана с оператором +?
            Ответить
            • a = b + c;

              Без мува:
              Временный объект Т (b + c) скопируется в а (медленно).

              С мувом:
              Временный объект Т (b + c) мувнеца в а (быстро, но сложно).
              Ответить
              • "a" уже имеет какое-то значение что ли?
                тогда да
                Ответить
                • А если никакого не имеет, тогда что? Там же для такого кейса вроде бы свой тип инициализации, да?
                  Ответить
                  • https://en.cppreference.com/w/cpp/language/copy_initialization

                    Насколько я понял, если у тебя нет мове-конструктора, то даже в пустое А у тебя произведется копирование, будет дикий оверхед и проц сгорит, поэтому всегда надо делать мове-семантику.
                    Ответить
                    • В C++ важно ня путать "=" и "=": первое — это оператор присваивания, который вызывает operator=(const T & other), а второе — это просто языковая конструкция-инициализация:
                      T a = b + c;  // Инициализация
                      a = b + c;  // Присваивание

                      Так вот в случае иняциализации в новых стандартах сработает mandatory copy elision (https://en.cppreference.com/w/cpp/language/copy_elision), и лишние копирование гарантированно ня вызовется.
                      Ответить
                      • А в старых нет?) В старых бы сначала создалось "a" (с каким значением?) а потом перезаписалось бы?

                        Это странно
                        Ответить
                        • В старых это было не обязательно. В них мог создаться временный объект (который вернул оператор+), затем a инициализировался копирующим конструктором из временной переменной. Затем временная переменная уничтожалась.
                          Ответить
                          • как же было написать в старых чтобы не по пидрски?

                            T a(b+ c) ?
                            Ответить
                            • Написать надо было разработчикам компилятора, если они ещё не сделали эту оптимизацию сами.

                              В этом варианте тоже а+b могло бы создать временную переменную, которая использовалась бы в копирующем конструкторе.
                              Ответить
                              • Какой пиздец) А если у меня конструктор тяжелый? И деструктор?
                                Как вообще люди писали на С++ двадцать лет назад?

                                Спец. фабричный метод делали?
                                Ответить
                                • Что-нибудь в этом духе:
                                  T a(b);
                                  a += c
                                  Ответить
                                  • T придется делать м*табельный
                                    Ответить
                                    • В крестах редко иммутабельные типы делают. const въеби да и всё, если хочешь чтобы значение не менялось.
                                      Ответить
                                      • Точно) У меня от помоечных япов без const в голове малость насрано, и я всё время забываю, что ператор += может быть и не const, а все остальные, ничего не меняющие методы, const
                                        Ответить
          • Нят, мутабельный оператор + — это крайне неинтуитивная подлянка, примерно как постфиксный operator++, возвращающий уже изменённый объект; яндере-тян, читающая такой код, будет очень огорчена.

            Для производительности обычно каждый operatorX реализуют через соответствующий operatorX=, примерно так:
            T & operator+=(const T & other)
            {
                // ...тяжёлые операции, модифицирующие this...
                return *this;
            }
            
            T operator+(const T & other) const
            {
                T temp(*this);
                temp += other;
                return temp;  // Нядеемся на NRVO
            }

            Тогда кому нядо производительность — тот сам будет заводить буфера и вызывать +=.
            Ответить
            • А чем плох мувающий плюс? Куски временных объектов сможет реюзать да и случайно его не вызвать.

              Для списков каких-нибудь вообще норм, имхо.
              Ответить
              • Не мувающий, а мутабельный. Мувающий вроде такого:
                T operator+(T && other) const {
                    T temp(std::move(other));
                    temp += *this;  // Если + симметричный
                    return temp;
                }

                — как раз нормально. А мутабельный — это примерно так:
                T & operator+(const T & other) {
                    this->something += other.something;
                    return *this;
                }
                Ответить
                • Это же отличный способ заставить пользователя твоей либы почитать документацию! Потом из неё он узнает, что операторы || и && тоже перегружены и писать ( (x = myObjectFactory.create()) || KillAllHumans() ) не стоило. Выяснит, что std::addressof существует не зря и нужно использовать его а не перегруженный &. Жаль, тернарники нельзя перегружать и запятую починили.
                  Ответить
                  • Amateurs! В Coq можно переопределить пробелы, скобки и чёрта лысого.
                    Ответить
                    • Непарные скобки можно?
                      Ответить
                      • Конечно:

                        Infix "(" := eq (at level 10).
                        
                        Check 1 ( 2.
                        Ответить
                        • Офигенно. А если джве нотации подходят к одному и тому же коду, то будет ошибка?
                          Ответить
                          • Не обязательно, парсер сначала по приоритетам попытается разрулить.
                            Ответить
                            • Infix "(" := eq (at level 10).
                              
                              Check ( 1 ( 2). (* работает как надо *)
                              Ответить
                    • А аналог крестовым неймспейсам там есть?
                      Ответить
                      • Для нотаций там есть scopes, а функции из модулей не обязательно явно импортировать:

                        Infix "(" := eq (at level 10, only parsing) : foo.
                        Delimit Scope foo with foo.
                        Open Scope foo. (* let the madness begin *)
                        Check ( 1 ( 2).
                        
                        Require MyModule.
                        Module M := MyModule.
                        
                        M.pitooshnya.
                        Ответить
      • > Что это за класс? Зачем он нужен?
        NIH

        > Почему его нельзя заменить std::string?
        NIH

        > Почему его нельзя заменить классом-композитом с std::string?
        NIH

        > Почему его нельзя заменить классом-наследником std::string?
        NIH

        > Что делать, когда понадобится хранить строки из wchar_t?
        Страдать Изобретать ещё один класс. Job Security
        Ответить
        • Что это такое?
          (Хуй! Хуй! Хуй!)
          Что тебе приснилось?
          (Хуй! Хуй! Хуй!)
          Как тебе живётся
          (Хуй! Хуй! Хуй!)
          Вместе с яйцами?
          В облаках летает!
          (Хуй! Хуй! Хуй!)
          Ласточек пугает!
          (Хуй! Хуй! Хуй!)
          Как тебе живётся
          (Хуй! Хуй! Хуй!)
          Между двух яйиц?

          https://youtu.be/pCnKChDwh1M
          Ответить
    • кастомный класс, прибитый гвоздём к char, не нужен
      Ответить
    • std::string отменили?
      Ответить
      • Да, там не было защиты от создания строки "nigger" и её отменили.
        Ответить

    Добавить комментарий