TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #753 5.78K
🔞 Если принимаете сырой указатель, как параметр - не забудьте проверить его на nullptr. Меньше будете голову ломать при будущем дебаге.

🔞 compareData зачем-то принимает параметры по значению. В смысле, понятно зачем: чтобы было double free, а вам было интереснее ревьюить. Лучше все-таки принимать по константной ссылке аргументы.

🔞 Поле buffer публичное как раз для того, чтобы к нему доступ имела compareData. Мы все-таки за инкапсуляцию и мир во всем мире. Поле надо сделать приватным, а compareData другом. А еще лучше убрать compareData и определить нативный оператор сравнения.

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

🔞 Data имеет конструктор от одного аргумента и лучше бы его сделать explicit. В таком случае, чтобы запретить неявные преобразования.

🔞 Многие отметили, что класс стоит пометить как final. Видимо это какой-то кодстайл, чтобы запретить другим классам наследоваться от этого. Причина, как я понял, это отсутствие виртуального деструктора. Поэтому если кто-то хочет отнаследоваться от класса, то он явно видит, что пока классом нельзя пользоваться полиморфно, убирает final и добавляет виртуальный деструктор.

Все же от Data можно безопасно наследоваться, если не использовать потом наследников полиморфно. А при добавлении виртуального метода можно и самому понять, что надо еще и деструктор соотвествующим сделать.

Мне final кажется оверкиллом для одиночных классов в небиблиотечном коде , но тут кто как привык.

Фух, на этом вроде все.

Вот что вышло по итогу исправлений:

class Data final {
private:
std::unique_ptr<char[]> buffer;
size_t buf_size = 0;

public:
Data(const char* input, size_t size)
: buf_size(size) {
if (input == nullptr && size != 0) {
throw std::invalid_argument("Input cannot be null for non-zero size");
}

if (size > 0) {
buffer = std::make_unique<char[]>(size);
std::copy(input, input + size, buffer.get());
}
}

template <size_t N>
explicit Data(const char (&str)[N])
: Data(str, N) {
}

// Копирующий конструктор
Data(const Data& other)
: Data{other.buffer.get(), other.buf_size} {
}

// Универсальное присваивание
Data& operator=(Data other) {
swap(*this, other);
return *this;
}

// Перемещающий конструктор
Data(Data&& other) noexcept {
swap(*this, other);
}

~Data() = default;

// Оператор сравнения
bool operator==(const Data& rhs) const noexcept {
return std::string_view{buffer.get(), buf_size} == std:;string_view{rhs.buffer.get(), buf_size()};
}

// Вспомогательная функция для обмена
friend void swap(Data& first, Data& second) noexcept {
using std::swap;
swap(first.buffer, second.buffer);
swap(first.buf_size, second.buf_size);
}
};

[[nodiscard]] bool compareData(const Data& data1, const Data& data2) noexcept {
return data1 == data2;
}


Пишите, если что забыл.

Critique your solution. Stay cool.

#cppcore #OOP #goodpractice #design
  • ❤ 36
  • 🔥 12
  • 👍 9
  • ❤‍🔥 1
  • 👎 1
More from @grokaemcpp
  1. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  2. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  3. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  4. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  5. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  6. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →