2016-07-04 2 views
0

Я хочу использовать уникальные и shared_ptr для обслуживания выделенной памяти. Но насколько я вижу, доступ к памяти (get, ...) всегда является константой и возвращает указатель const const, поэтому я не могу манипулировать хранящейся памятью.Как изменить память, защищенную std :: shared_ptr (unique_ptr)

Пример:

std::unique_ptr<int[]> ptr(new int[42]); 

memset(ptr.get(),0,42*sizeof(int)); //not possible ptr.get() returns const pointer 

Есть работа вокруг? Если нет способа манипулировать памятью, каковы причины дизайна, чтобы не предлагать такой интерфейс?

+1

Почему вы хотите использовать 'memset'? И зачем использовать 'std :: unique_ptr ' вместо 'std :: vector'? – TartanLlama

+0

вы не можете украсть память (взять на себя ответственность как release) из std :: vector – user1235183

+1

@ user1235183 это 'const pointer', а не' указатель на const', вы можете изменить содержимое, на которое оно указывает, без каких-либо проблем. Но вам могут потребоваться некоторые приведения, если вы хотите использовать c-функции, такие как memset. – PeterT

ответ

3

Функция подписи для std::unique_ptr::get является

pointer get() const;

тип pointer будучи «std::remove_reference<Deleter>::type::pointer, если этот тип существует, в противном случае T*»

Единственный const в том, что подпись является для самой функции, так что его можно называть на const std::unique_ptr<int> a;

Итак, ваше предположение and return const pointer не соответствует действительности. Вы можете изменить память, на которую указывает интеллектуальный указатель, с помощью указателя, полученного из его функции-члена get().

Кроме memset(ptr.get(),0,42*sizeof(int)); также хорошо и не нуждается в каких-либо слепки, потому что вы все еще можете неявно преобразовать любой указатель на пустой указатель в соответствии с this pointer-conversion rule:

A prvalue pointer to any (optionally cv-qualified) object type T can be converted to a prvalue pointer to (identically cv-qualified) void. The resulting pointer represents the same location in memory as the original pointer value. If the original pointer is a null pointer value, the result is a null pointer value of the destination type.

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

2

Теперь, когда понимаются механики std::unique_ptr<>::get(), вы можете увидеть некоторое значение в более идиоматическом алгоритме.

Возможно, это более читаемо, избегает бросков, будет работать, если вы передумаете о базовом хранилище и так же эффективны.

некоторые примеры:

std::fill(ptr.get(), ptr.get() + 42, 0); 

std::fill(&ptr[0], &ptr[42], 0); 

std::fill(std::addressof(ptr[0]), std::addressof(ptr[42]), 0); 

и с небольшой шаблонный:

for (auto& x : linear_range(ptr.get(), 42)) { 
    x = 0; 
} 

С поддержкой оптимизаций, все эти оценки к тому же эффективный код.

шаблонный здесь:

template<class I1, class I2> 
struct range_impl { 

    auto begin() const { return i1; } 
    auto end() const { return i2; } 
    I1 i1; 
    I2 i2; 
}; 

template<class I1, class I2> 
auto range(I1 i1, I2 i2) { 
    return range_impl<I1, I2> { i1, i2 }; 
} 

template<class I1> 
auto linear_range(I1 i1, std::size_t length) { 
    return range(i1, std::next(i1, length)); 
} 
Смежные вопросы