#c #optimization #smart-pointers #restrict-qualifier
#c #оптимизация #интеллектуальные указатели #ограничение-квалификатор
Вопрос:
Безопасно ли следующее?
struct K { ... }
struct A
{
A(int psize) : size(psize), foo(nullptr), bar(nullptr)
{
auto dataptr = (K*)_aligned_malloc(sizeof(K) * psize * 2, 32);
data = shared_ptr<K>(dataptr, ptr_fun(_aligned_free));
foo = data.get();
bar = data.get() psize;
}
K* __restrict foo;
K* __restrict bar;
private:
shared_ptr<K> data;
};
Обратите внимание на __restrict для foo и bar .
Цель состоит в том, чтобы выделенная память самоуничтожилась, когда все псевдонимы объектов исчезли.
{
A a(1000);
{
A o = a;
}
//a.foo is still valid
}
//a.foo is invalid
Ответ №1:
Здесь вам не нужны __restrict
квалификаторы, и на самом деле вы не должны их использовать, потому __restrict
что предполагается сообщить компилятору, что у вас нет никаких псевдонимов для одной и той же памяти, но на самом деле у вас есть псевдонимы — foo
и data
являются псевдонимами для одной и той же памяти.
Я думаю, что семантика вашего кода в порядке, в противном случае. Ваши условия a.foo по-прежнему действительны, а условия a.foo недопустимы, будут истинными.
Комментарии:
1.
__restrict
это только оптимизация компилятора, она не изменяет поведение вашей программы.2. Да. Надеялся, что логической гарантии того, что foo не будет изменен в другом месте, будет достаточно для __restrict (т.Е. Память имеет псевдоним, но я обещаю, что не изменю ее, кроме как из foo). Конечно, до тех пор, пока объект не умрет.
3. Дааааа…. Я думаю, вы должны быть очень осторожны при использовании __restrict таким образом. Если у вас есть только один экземпляр
A
, то, возможно, вам это сойдет с рук, но ваш вариант использования четко указывает на то, что вы хотите иметь возможность копировать-присваиватьA
, и в этом случае у вас есть память, на которую указывают дваshared_ptr
указателя s и два__restrict
указателя ed… очень плохая ситуация.4. Ах, я понимаю. Не рассматривал конструкцию копирования. Спасибо!
Ответ №2:
Это небезопасно, потому что malloc не вызывает конструктор, а free не вызывает деструктор. Чтобы это было безопасно, вам нужно вручную добавить эти вызовы:
A(int psize) : size(psize), foo(nullptr), bar(nullptr)
{
auto dataptr = (K*)_aligned_malloc(sizeof(K) * psize * 2, 32);
new(dataptr) K();
data = shared_ptr<K>(dataptr, [](K *k){ k->~K(); _aligned_free(k) ));
foo = data.get();
bar = data.get() psize;
}
Комментарии:
1. У K нет конструктора / деструктора: D Это МОДУЛЬ