Определить создаваемость объекта на куче
От: Went  
Дата: 04.10.22 10:52
Оценка:
Здравствуйте. Нужен трейт, чтобы определял, можно ли создать создать объект на куче используя стандартный new или placement new:
auto x = new X();
auto x2 = new (malloc(sizeof(X))) X();

По идее, ограничения два — должен быть публичный конструктор по умолчанию (или с аргументами по умолчанию..., но это не важно), и оператор new не должен быть каким-то образом запрещён.
Поэтому, стандартный std::is_default_constructible не подходит (он, я так понимаю, проверяет возможность создания на стеке и поэтому учитывает доступность деструктора).
Есть какой-то прямой и очевидный способ проверить это, а то велоипеды работают плохо и не везде
Re: Определить создаваемость объекта на куче
От: rg45 СССР  
Дата: 04.10.22 11:10
Оценка: 15 (2) +1
Здравствуйте, Went, Вы писали:

W>Здравствуйте. Нужен трейт, чтобы определял, можно ли создать создать объект на куче используя стандартный new или placement new:

W>
W>auto x = new X();
W>auto x2 = new (malloc(sizeof(X))) X();
W>


Как я догадываюсь, концепты не предлагать? Тогда старый добрый SFINAE:

http://coliru.stacked-crooked.com/a/c86ada698918bdfc

#include <iostream>
#include <type_traits>

template <typename T, typename = T*>
struct is_new_available : std::false_type {};

template <typename T>
struct is_new_available<T, decltype(new T())> : std::true_type {};

struct A
{
    static void* operator new(size_t) = delete;
};

int main()
{
    std::cout << is_new_available<int>::value << std::endl; // -> 1
    std::cout << is_new_available<A>::value << std::endl; // -> 0
}


Таким же образом проверяется и placement new.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Определить создаваемость объекта на куче
От: Went  
Дата: 04.10.22 12:07
Оценка:
Здравствуйте, rg45, Вы писали:

R>Как я догадываюсь, концепты не предлагать? Тогда старый добрый SFINAE...

Супер, работает! Честно сказать, я искал ошибку в чужом коде, и там было сделано приблизительно так (обрати внимание на void):

#include <iostream>
#include <type_traits>

template <typename T, typename = void>
struct is_new_available : std::false_type {};

template <typename T>
struct is_new_available<T, void(decltype(new T()))> : std::true_type {};


В результате, для объектов, у которых определен пользовательский оператор new и защищенный деструктор, VS2019 кидало ошибку, так как почему-то пыталось получить доступ к деструктору (точнее, из-за SFINAE молча разрешалось в общую форму шаблона). Я вроде пытался сделать без void, но что-то тоже не работало.
Re[3]: Определить создаваемость объекта на куче
От: vopl Россия  
Дата: 04.10.22 12:26
Оценка: 4 (1)
Здравствуйте, Went, Вы писали:

W>Здравствуйте, rg45, Вы писали:


R>>Как я догадываюсь, концепты не предлагать? Тогда старый добрый SFINAE...

W>Супер, работает! Честно сказать, я искал ошибку в чужом коде, и там было сделано приблизительно так (обрати внимание на void):

W>
W>#include <iostream>
W>#include <type_traits>

W>template <typename T, typename = void>
W>struct is_new_available : std::false_type {};

W>template <typename T>
W>struct is_new_available<T, void(decltype(new T()))> : std::true_type {};
W>


W>В результате, для объектов, у которых определен пользовательский оператор new и защищенный деструктор, VS2019 кидало ошибку, так как почему-то пыталось получить доступ к деструктору (точнее, из-за SFINAE молча разрешалось в общую форму шаблона). Я вроде пытался сделать без void, но что-то тоже не работало.


Так у тебя вторым параметром шаблона заявляется функция void(T*), для нее чтобы вывести T* идет обращение на operator new, если он закрыт или удален — будет ошибка Это я прогнал. Просто детектор не работает как должно в этом случае, не правильно определяет. И, видимо, на основании не правильной детекции, уже в другом коде идет попытка вызова new и там возникает ошибка..
Вот так работает:
template <typename T, typename = void>
struct is_new_available : std::false_type {};

template <typename T>
struct is_new_available<T, std::void_t<decltype(new T())>> : std::true_type {};
Отредактировано 04.10.2022 12:39 vopl . Предыдущая версия .
Re[3]: Определить создаваемость объекта на куче
От: rg45 СССР  
Дата: 04.10.22 13:49
Оценка: +1
Здравствуйте, Went, Вы писали:

W>я искал ошибку в чужом коде, и там было сделано приблизительно так (обрати внимание на void):


W>
W>#include <iostream>
W>#include <type_traits>

W>template <typename T, typename = void>
W>struct is_new_available : std::false_type {};

W>template <typename T>
W>struct is_new_available<T, void(decltype(new T()))> : std::true_type {};
W>


Ну это вообще что-то странное — к void можно привести ОБЪЕКТ какого-то типа (или ссылку), а здесь в качестве аргумента пытаются использовать непостредствено тип, а не объект. Конечно, это не может скомпилиться, ни при каком T. Вероятно, вместо void хотели использовать std::void_t, а потом перемудрили.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Определить создаваемость объекта на куче
От: σ  
Дата: 04.10.22 14:15
Оценка: +1
R>Ну это вообще что-то странное — к void можно привести ОБЪЕКТ какого-то типа (или ссылку)
Выражение.
Re[5]: Определить создаваемость объекта на куче
От: rg45 СССР  
Дата: 04.10.22 14:20
Оценка:
Здравствуйте, σ, Вы писали:

R>>Ну это вообще что-то странное — к void можно привести ОБЪЕКТ какого-то типа (или ссылку)

σ>Выражение.

Ты прав, как всегда.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Определить создаваемость объекта на куче
От: vopl Россия  
Дата: 04.10.22 14:27
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Went, Вы писали:


W>>я искал ошибку в чужом коде, и там было сделано приблизительно так (обрати внимание на void):


W>>
W>>#include <iostream>
W>>#include <type_traits>

W>>template <typename T, typename = void>
W>>struct is_new_available : std::false_type {};

W>>template <typename T>
W>>struct is_new_available<T, void(decltype(new T()))> : std::true_type {};
W>>


R>Ну это вообще что-то странное — к void можно привести ОБЪЕКТ какого-то типа (или ссылку), а здесь в качестве аргумента пытаются использовать непостредствено тип, а не объект. Конечно, это не может скомпилиться, ни при каком T. Вероятно, вместо void хотели использовать std::void_t, а потом перемудрили.


Это не приведение к void, это тип функция void(Arg), и если основной шаблон чуть подправить то это все работает
template <typename T, typename = void(T*)>
struct is_new_available : std::false_type {};

template <typename T>
struct is_new_available<T, void(decltype(new T()))> : std::true_type {};
Re[5]: Определить создаваемость объекта на куче
От: rg45 СССР  
Дата: 04.10.22 14:47
Оценка:
Здравствуйте, vopl, Вы писали:

V>Это не приведение к void, это тип функция void(Arg), и если основной шаблон чуть подправить то это все работает


Это понятно, что можно реализовать и так и эдак, но если судить по объявлению primary template, похоже, пытались сделать имненно приведение. Хотя, даже если бы это приведение удалось, все равно вышел бы облом, поскольку шаблон ожидает тип, в качестве параметра
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 04.10.2022 15:15 rg45 . Предыдущая версия . Еще …
Отредактировано 04.10.2022 14:51 rg45 . Предыдущая версия .
Re[4]: Определить создаваемость объекта на куче
От: Went  
Дата: 04.10.22 17:38
Оценка:
Здравствуйте, rg45, Вы писали:

R>Ну это вообще что-то странное — к void можно привести ОБЪЕКТ какого-то типа (или ссылку), а здесь в качестве аргумента пытаются использовать непостредствено тип, а не объект. Конечно, это не может скомпилиться, ни при каком T. Вероятно, вместо void хотели использовать std::void_t, а потом перемудрили.

Ох, это чисто моя описка, было вот так (это вариант для placement_new):
decltype(void(new (std::declval<T*>()) T()))

То есть умозрительный результат вызова placement new приводился явно к void. Я заменял это на такое
decltype(static_cast<void>(new (std::declval<T*>()) T()))

допуская именно ошибку трактовки "то ли функция, то ли приведение", но ничего не менялось — студия упорно хотела доступа к деструктору T. При этом ideone на GCC8 пережёвывал это нормально.
Re[5]: Определить создаваемость объекта на куче
От: rg45 СССР  
Дата: 04.10.22 18:19
Оценка: 14 (2)
Здравствуйте, Went, Вы писали:

W>Ох, это чисто моя описка, было вот так (это вариант для placement_new):

W>
W>decltype(void(new (std::declval<T*>()) T()))
W>

W>То есть умозрительный результат вызова placement new приводился явно к void. Я заменял это на такое
W>
W>decltype(static_cast<void>(new (std::declval<T*>()) T()))
W>

W>допуская именно ошибку трактовки "то ли функция, то ли приведение", но ничего не менялось — студия упорно хотела доступа к деструктору T. При этом ideone на GCC8 пережёвывал это нормально.

Я думаю, что причина в том, что в этом случае использование оператора new является не полным выражением, а подвыражением. В стандарте рыться лениво, но, думаю, вот этому ресурсу можно доверять:

https://en.cppreference.com/w/cpp/language/decltype

Because no temporary object is created, the type need not be complete or have an available destructor, and can be abstract. This rule doesn't apply to sub-expressions: in decltype(f(g())), g() must have a complete type, but f() need not.

--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: Определить создаваемость объекта на куче
От: Went  
Дата: 05.10.22 06:01
Оценка:
Здравствуйте, rg45, Вы писали:

R>Я думаю, что причина в том, что в этом случае использование оператора new является не полным выражением, а подвыражением. В стандарте рыться лениво, но, думаю, вот этому ресурсу можно доверять:

R>https://en.cppreference.com/w/cpp/language/decltype
R>

R>Because no temporary object is created, the type need not be complete or have an available destructor, and can be abstract. This rule doesn't apply to sub-expressions: in decltype(f(g())), g() must have a complete type, but f() need not.

Да, наверняка, так и есть. Удивительно, как ты это раскопал. Осталось выяснить, почему нужен доступ к деструктору в выражении, в котором ничего не разрушается? И почему в других компиляторах не требуется. Очередная бага студии?
Re[7]: Определить создаваемость объекта на куче
От: rg45 СССР  
Дата: 05.10.22 07:15
Оценка:
Здравствуйте, Went, Вы писали:

W>Да, наверняка, так и есть. Удивительно, как ты это раскопал. Осталось выяснить, почему нужен доступ к деструктору в выражении, в котором ничего не разрушается? И почему в других компиляторах не требуется. Очередная бага студии?


Да, похоже, что бага. Ведь результатом (под)выражения является указатель — который всегда является полным типом, даже когда указывает на неполный. И с деструктором указателя тоже никаких вопросов возникать не должно.
--
Не можешь достичь желаемого — пожелай достигнутого.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.