2015-03-01 2 views
1

Я написал класс MyString и MyStringConst. Теперь мне нужно время от времени передавать MyString как MyStringConst, следовательно, перегружать оператор переноса. Я написал этоC++ reinterpret_cast - это всегда будет работать правильно?

MyString::operator const MyStringConst &() const 
{ 
    return reinterpret_cast<const MyStringConst &>(*this); 
} 

MyString имеет эти данные

char * str; 
int length; 
volatile int hashCode; 
int bufferSize; 

MyStringConst имеет эти данные

const char * c_str; 
int length; 
volatile int hashCode; 

Плюс есть некоторые методы, которые в обеих строках можно пересчитать хэш-код.

Правильно ли это код. Я тестировал его на MSVC 2013, и он работает правильно, но я понятия не имею, можно ли его использовать в производственном коде, который может быть скомпилирован с помощью другого компилятора.

+7

Если это два совершенно разных класса, вы не можете просто переосмыслить их. данные могут быть смещены и т. д. ... в чем смысл MyStringConst. Почему бы просто не использовать const MyString? – thang

+0

@thang MyString выделяет новую строку, MyStringConst not (только оболочка вокруг указателя), но мне нужно их сравнить. –

+0

На практике он будет PROBABLY работать во всех компиляторах, с которыми вы когда-либо столкнетесь в реальной жизни. Но в строгих условиях langauge-lawyer определенно не гарантируется работа. –

ответ

2

Общая исходная последовательность элемента данных различна, и C++ не дает никаких гарантий относительно макета в этом случае, даже если типы отличаются только квалификацией const. В противном случае гарантии для union s будут фактически означать, что типы должны иметь общий макет, если они являются стандартными типами макета (согласно примечанию в пункте 9.5 [class.union]).

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

MyString::operator MyStringConst() const { 
    return MyStringConst(str, length); 
} 

Объект MyString еще должен жить до тех пор, пока результат преобразования, но это не отличается от случая с использованием reinterpret_cast.

BTW, volatile на hashCode не рекомендуется: единственный эффект, который у него будет, заключается в замедлении работы программы. Я предполагаю, что вы пытаетесь использовать его для достижения синхронизации между потоками, но в C++ volatile не помогает в этом: вы получаете гонку данных при записи элемента в одном потоке, к которому также обращаются несинхронизированные в другом потоке. Вы наделили бы членов

std::atomic<int> hashCode; 

вместо этого.

+1

Some nitpicking: In общие, соответствующие типы ** могут ** различаться по const-квалификации и быть частью общей исходной последовательности, согласно [9.2p16]; они просто должны быть совместимы с макетами, и, согласно [3.9p11], это включает типы с различной cv-квалификацией. Здесь, однако, соответствующие первые члены являются * указателями на совместимые с макетами типы *, и, чтобы загрязнять воды, стандарт не строго называет такие указатели «совместимыми с макетами». – bogdan

+1

Он, однако, говорит что-то, что должно быть эквивалентно в [3.9.2p3]: * [...] Указатели на совместимые с макетами типы должны иметь одинаковые представления представления и выравнивания значений [...] *. Я думаю, что это должно сделать этот случай достаточно точным, хотя в строгой поэтапной интерпретации стандарта два типа не имеют общей исходной последовательности. Я бы рискнул предположить, что * намерение * стандарта заключается в том, что они делают. – bogdan

+0

Просто нашел дополнительную индикацию: сноска к [3.9.3p1]: * Те же требования к представлению и выравниванию подразумевают взаимозаменяемость в качестве аргументов функций, возвращаемых значений из функций и нестатических членов данных объединений. * – bogdan

Смежные вопросы