Forwarded from Ваня Не проблема
Ребятки, а подскажите, что тут надо поправить, чтобы деструктор B вызвался?
😁8🤔3
std::unique_ptr является практически универсальным афинным хэндлом.
Его можно использовать как move-only RAII обёртку для практически любого хэндла, не переплачивая по памяти.(А в человеческих ABI - и по скорости тоже.) Главное, чтобы у хэндла было какое-нибудь null-значение.
Особенно полезно при оборачивании сишных API.
Допустим, у нас есть OpenGL текстуры. Вообще OpenGL использует
Эта обёртка невладеющая. Она удовлетворяет концепту NullablePointer, типы которого умеет оборачивать
Заметим, что мы не переплатили:
Теперь напишем кастомный deleter для
Как известно, если существует тип
Напишем наконец владеющую обёртку:
Уже можно пользоваться! осталось только заметить, что мы написали замену
Выделение из этого примера бойлерплейта в утилитарные шаблоны предоставляется читателю как упражнение.
Его можно использовать как move-only RAII обёртку для практически любого хэндла, не переплачивая по памяти.
Особенно полезно при оборачивании сишных API.
Допустим, у нас есть OpenGL текстуры. Вообще OpenGL использует
GLuint для почти всех хэндлов, так что сделаем типобезопасную обёртку:struct GL_texture_handle {
GLuint id = 0;
GL_texture_handle() = default;
GL_texture_handle(std::nullptr_t) {}
explicit operator bool() const { return id != 0; }
bool operator==(const GL_texture_handle&) const = default;
};Эта обёртка невладеющая. Она удовлетворяет концепту NullablePointer, типы которого умеет оборачивать
unique_ptr. Заметим, что этому концепту не нужно разыменование (для непрозрачных хэндлов оно бессмысленно), а нужно только null-значение и интерфейс к нему через сравнимость с nullptr. Причём это null-значение может быть таким, каким требует предметная область: 0, -1, что-нибудь нечётное, особое значение структуры и т.п. Главное, чтобы мы думали про него, когда нам говорят про nullptr.Заметим, что мы не переплатили:
// 4 на любой платформе согласно спеке OpenGL
static_assert(sizeof(GL_texture_handle) == sizeof(GLuint));
Теперь напишем кастомный deleter для
unique_ptr.struct GL_texture_deleter {
using pointer = GL_texture_handle;
void operator()(pointer handle) const {
glDeleteTextures(1, &handle.id);
}
};Как известно, если существует тип
Deleter::pointer, то std::unique_ptr<T, Deleter> будет хранить внутри себя не T*, а Deleter::pointer. Мы вообще проигнорируем T.Напишем наконец владеющую обёртку:
using Unique_GL_texture = std::unique_ptr<void, GL_texture_deleter>;
static_assert(sizeof(Unique_GL_texture) == sizeof(GLuint)); // !!!
Уже можно пользоваться! осталось только заметить, что мы написали замену
std::default_delete, но не написали замены std::make_unique.Unique_GL_texture make_gl_texture(GLenum target) {
GL_texture_handle handle;
glCreateTextures(target, 1, &handle.id);
return Unique_GL_texture(handle);
}Выделение из этого примера бойлерплейта в утилитарные шаблоны предоставляется читателю как упражнение.
👍8
Прогнать Ве Крест Крест через @ZoVifyBot
🥴6👏1
прислать в gcc патч, делающий -ferror-limit алиасом на -fmax-errors
прислать в clang патч, делающий -fmax-errors алиасом на -ferror-limit
прислать в clang патч, делающий -fmax-errors алиасом на -ferror-limit
🤔4👏3🥴2
vkCmdBegin(cb, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
vkCmdColor3f(cb, 1.f, 0.f, 0.f);
vkCmdVertex2f(cb, -0.5f, -0.5f);
vkCmdColor3f(cb, 0.f, 1.f, 0.f);
vkCmdVertex2f(cb, 0.f, 0.5f);
vkCmdColor3f(cb, 0.f, 0.f, 1.f);
vkCmdVertex2f(cb, 0.5f, -0.5f);
vkCmdEnd(cb);
if (it != nullptr && *it != nullptr && **it != nullptr && ***it != nullptr) {
(**it)(this);
}🤣11
template <class T, class E>
struct Result : public Either<T, E> {
template <class V>
Result(V&& v) : Either<T, E>(std::forward<V>(v)) {
}
template <class V>
Result(const V& v) : Either<T, E>(v) {
}
auto Ok() const noexcept -> bool {
return this->template Is<T>();
}
auto Unwrap() -> T& {
try {
return this->template As<T>();
} catch (...) {
throw this->template As<E>();
}
}
auto Err() -> E {
return this->template As<E>();
}
auto operator!() -> T& {
return Unwrap();
}
};
auto Res() -> monad::Result<monad::Unit, err::RuntimeError> {
return err::RuntimeError("LOL");
}
auto Throws() -> void {
!Res();
}
🔥4
#include <string>
#include <fmt/format.h>
template<typename F>
struct Scope_exit {
F f;
Scope_exit(F f): f(std::move(f)) {}
~Scope_exit() { f(); }
};
auto make_string() {
std::string result;
Scope_exit guard = [&] {
fmt::println("About to return '{}'", result);
};
for (int i = 0; i < 20; i++) {
result += std::to_string(i);
}
return result;
}
int main() {
auto s = make_string();
}
$ # Either behavior is legal of a C++ compiler
$ g++ a.cpp -lfmt -o a && ./a
About to return '012345678910111213141516171819'
$ g++ a.cpp -lfmt -o a -fno-elide-constructors && ./a
About to return ''
🥴3👍2
auto(*foo)(size_t)->void* {
malloc //
};🥰6
Постироничные идеи для ебаного C++
&*iovecs_.begin()
using T = std::iter_value_t<decltype(iovecs_.begin())>;
if constexpr(std::is_same_v<std::vector<T>, decltype(iovecs_)>) {
auto* ptr =reinterpret_cast<T*>(iovecs_.begin());
}