Преобразование из std :: vector того же типа параметра, но с другим постоянным квалификатором

вопрос довольно прост, является ли вообще безопасным статическое приведение (или какое-либо другое приведение) от

std::vector< Foo >

в

std::vector< const Foo >

бинарно, я не понимаю, почему нативные типы будут отличаться, в конце концов, const это ограничение языка, которое не должно влиять на размер элемента, или я так думаю

я могу сделать

std::vector< const Foo >& someFunc()
{
std::vector< Foo >& ref = ...
return *reinterpret_cast<std::vector< const Foo >*>(& ref);
}

и не волнуетесь, что это потопит чью-то лодку? или это вообще небезопасно?

-1

Решение

Игнорируя то, что вы сказали на данный момент std :: vector, и притворившись, что у вас есть другая, менее четко определенная реализация вектора. Ваш код был бы технически небезопасен не потому, что T а также T const совсем другие, но потому что язык C ++ позволяет vector<T> а также vector<T const> быть специализированным в совершенно разных направлениях. Рассмотрим следующий код:

#include <iostream>

template <class T>
struct vector {
T* start_;
T* end_;
T* cap_end_;
};

template <class T>
struct vector<T const> {
bool gotcha_;
T* start_;
T* end_;
T* cap_end_;
};

struct foo { };

int
main()
{
std::cout
<< sizeof(vector<foo>) << '\n'
<< sizeof(vector<foo const>) << '\n'
;
}

Обратите внимание, что есть и другие более пагубные изменения, которые могут сделать вашу жизнь несчастной. Например, следующее, где члены переупорядочены:

#include <iostream>

template <class T>
struct vector {
T* start_;
T* end_;
T* cap_end_;
};

template <class T>
struct vector<T const> {
T* end_;
T* cap_end_;
T* start_;
};

template <class T>
long size(vector<T> const& v)
{
return v.end_ - v.start_;
}

struct foo { };

int
main()
{
vector<foo> v;
v.start_ = new foo[10];
v.end_ = v.start_ + 1;
v.cap_end_ = v.start_ + 10;std::cout
<< size(v) << '\n'
<< size(*reinterpret_cast<vector<foo const>*>(&v)) << '\n'
;

return 0;
}

Что касается std :: vector, я недостаточно знаком с тонкими деталями спецификации стандартной библиотеки, чтобы знать, будут ли такие специализации соответствовать или нет. Возможно, кто-то более хорошо разбирающийся в стандарте может прокомментировать.

Обратите внимание на то, что я сказал в ответ на Приведение шаблонного класса к более общей специализации может помочь объяснить эту проблему.

Чтобы ответить на ваш вопрос об обнаружении специализаций, есть способы сделать ваш код небезопасным, не используя специализаций класса, а перегружая функции, не являющиеся членами, и я не уверен, как вы это обнаружите. Например, в следующем:

#include <iostream>

template <class T>
struct vector {
T* start_;
T* end_;
T* cap_end_;
};template <class T>
void init(vector<T>& v, size_t sz, size_t cap)
{
v.start_ = new T[cap];
v.end_ = v.start_ + sz;
v.cap_end_ = v.start_ + cap;
}

template <class T>
void init(vector<T const>& v, size_t sz, size_t cap)
{
v.end_ = new T const[cap];
v.cap_end_ = v.end_ + sz;
v.start_ = v.end_ + cap;
}

template <class T>
long size(vector<T>& v)
{
return v.end_ - v.start_;
}

template <class T>
long size(vector<T const>& v)
{
return v.cap_end_ - v.end_;
}

struct foo { };

int
main()
{
vector<foo const> v;
init(v, 1, 10);

std::cout
<< size(v) << '\n'
<< size(*reinterpret_cast<vector<foo>*>(&v)) << '\n'
;
}

Хватит с плохих новостей. Хорошей новостью является то, что если вы хотите взять существующий объект с общим интерфейсом и ограничить или настроить то, что можно сделать с этим объектом, есть несколько простых, безопасных и приемлемых способов сделать это. Посмотрите на std :: stack http://www.sgi.com/tech/stl/stack.html или альтернативно этот ответ https://stackoverflow.com/a/994925/453436 в Что такое прокси-класс в C ++

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]