2010-08-25 2 views
3

Мне было интересно, почему не может быть тип данных void, который не является указателем?C++ Void non-pointer

Конечно, вы могли бы пройти весь определенный размер вещи, имея

void4 
void8 
void32 

и только разрешают «отбрасываемой» типа аннулируются данных к другому классу, если его размер равен или под с размером классов ,

Есть ли что-то, что мне не хватает, или комитет C++ просто считает это плохой практикой?

EDIT:

Я не объяснил себя очень хорошо, так что я дам пример ее использования:

main() 
{ 
    /* 

    Lets make a list of unknown elements 

    std::string is 8 bytes, and float is 4 
    bytes, so we'll reserve 8 byte sequences 

    */ 

    vector<void8> elements; 

    elements.push_back((void8) string("First string element")); 

    elements.push_back((void8) float(5.76)); 

    elements.push_back((void8) string("Third string element")); 

    // Ect. 

    cout << (string) elements[0]; 
    cout << (float) elements[1]; 
    cout << (string) elements[2]; 
    cout << (float) elements[2]; // Garbage 


    void1 data; 

    data = (void1) bool(1); 
    data = (void1) unsigned int(80094); // Error, not enough size 
} 

Его назвали недействительным, потому что вы не знаете, какой тип это в настоящее время хранится, подобно указателю void.

+3

Что было бы полезно для этого, какая проблема? – nos

+0

Я должен уточнить, он будет использоваться аналогично указателю void - возможно, void - не лучшее имя для него. – Tomas

+0

void8 будет типом с 8 байтами, который может быть перенесен на любой тип в пределах 8 байтов в любой момент времени. – Tomas

ответ

3

В строго типизированном языке все данные имеют тип, поэтому нет понятия «пустота» в качестве типа данных. В C и C++ это значения либо «нет данных» (как возвращаемое значение), либо «данные, тип которых вы не знаете» (в качестве цели указателя).

Вы предлагаете промежуточное состояние «данных, тип которых вы не знаете, но размер которого вы делаете», предположительно как непрозрачную версию типа, которую вы передаете по значению. Помимо того, что вы довольно опасны (поскольку вам нужно вручную обновлять весь код с помощью непрозрачного типа при изменении размера реального типа), это уже можно сделать без добавления странных расширений к языку, например:

struct void8 { char bytes[8]; }; 

Этот мог быть использовано в сочетании с reinterpret_cast передать типы POD вокруг, как непрозрачные комочки, во многом так, как вы предлагаете. Использование его с не-POD-типами, скорее всего, вызовет неопределенное поведение, чем использование void* для обозначения типов, отличных от POD.

Было бы безопаснее и более идиоматично обрабатывать непрозрачные типы в качестве указателей или ссылок на именованные типы, которые были объявлены, но не определены, или что-то вроде boost::any, если вы хотите семантику значений. В C++ редко используется «пустота» в качестве типа заполнителя.

+0

Я думаю, вы имеете в виду 'struct void32', а не' struct void8'? –

+0

@therefromhere: это зависит от того, считаете ли вы биты или байты. В недавнем редактировании вопроса подразумеваются байты, поэтому я буду придерживаться этого. –

+0

Это не решение плохо сформулированной проблемы. Каким будет использование такого класса? Сможете ли вы сохранить содержимое других объектов в этой структуре? 'Reinterpret_cast'? Пример кода в вопросе не будет работать из коробки, и даже если вы сделаете так * работу * с соответствующим кастингом, семантика по-прежнему не правильная. Для всех типов non-pod вы будете находиться в зоне неопределенного поведения. –

2

Что будет означать тип данных «пустота»? Я не думаю, что есть действующий, так что, вероятно, поэтому его не существует.

+1

-1. Я не думаю, что это ответ, я думаю, что это должен быть комментарий. – Default

+0

@ Майкл: Это ответ в форме вопроса. Я подразумеваю, что «это не имеет смысла, поэтому его не существует». –

+0

Было бы лучше, если бы это был хайку. – SurDin

2

Что недействительно? Это ничего, пустота. Void32, lol! void используется для обозначения функции, которая ничего не возвращает. В других языках есть ключевое слово «procedure» или «sub». Указатель на void - указатель на неизвестный (второе использование void). Это две цели.

Обновление: Я думаю, автор хочет обозначить неизвестный тип с известным размером. void32 * - указатель на какой-либо объект с размером 32 бита, void8 * - указатель на 8-битные объекты и т. д. Но он легко эмулируется с помощью int32 *, char * без расширения языка.

+3

'void8' слишком велик - я хочу' void7' –

+0

Реальный вопрос: могу ли я хранить 'void32' в' void4'? В конце концов, если он просто содержит void, нет причин, по которым он не должен вписываться в меньший тип данных. – jalf

0

Наличие типа данных в пустоте излишне усложняло бы вещи. и более того, что будет делать тип данных, если он называется void.

Я думаю, вы имеете в виду тип данных, который может функционировать как пустой, но вы можете изменить имя и не называть его void.

2

Что вы ищите уже существует. Он называется char. Массив из char может использоваться для хранения неизвестных объектов, потому что char в основном является именем C++ для байта. Таким образом, чтобы хранить неизвестные или переменные типы объектов в одном массиве, вы используете массив байтов, а не массив ничего, что было бы void.

Точка в указателе void заключается в том, что мы не знаем, на что он указывает. Мы не знаем размер объекта, на который он указывает. Так что void4 не имеет большого смысла. Мы больше не «пусто», если знаем размер объекта. Единственное, что мы можем сделать с неизвестным объектом, это указать на него. Мы не можем хранить его в любом месте, потому что мы не знаем, является ли он объектом POD, и мы не знаем, насколько он величен или его требования к выравниванию. Поэтому мы, конечно, не храним его в массиве. Все, что мы можем сделать, это создать указатель на него, и у нас уже есть указатели void.

И, конечно же, забавный вопрос:

Какой типа T здесь?

void foo(void* p) { 
    T q = *p; 
} 

void4? void32? Или просто void? Насколько большой должен быть объект? Что мы знаем об этом? Это тип POD?

+0

Достаточно справедливо - имя не является правильным – Tomas

8

Это называется boost :: variant или boost :: any. Это размер максимально допустимого типа данных + sizeof (указатель) и полностью безопасен по типу.

+0

+1 Это, скорее всего, то, что ОП действительно ищет. –

+0

Я знаю, что повышение является альтернативой, но мне интересно, почему вы не можете использовать метод, который я изложил, учитывая, что это будет дешевле по памяти. – Tomas

+4

@ Томас Кокис: Потому что вы будете ссылаться на огромное количество неопределенного поведения memcpying вокруг классов и такие, которые нуждаются в нетривиальной конструкции, разрушении и т. д. Кроме того, вам нужно будет создавать сотни миллионов объектов, чтобы заметить sizeof (указатель). Наконец, это было бы совершенно непереносимо, поскольку sizeof (std :: string) не определен. Данные - это не только биты и байты, это требует огромного количества метаданных времени компиляции, которые будут использоваться безопасно. Либо вы храните эти данные во время выполнения (boost :: variant), либо вы делаете его одним конкретным типом во время компиляции, поэтому вам не нужно его хранить. – Puppy

0

void* не является указателем, который является недействительным, как в недействительном. Это указатель на void, так как в нем ничего нет.

Тип типа void сам определяется отсутствием значения. В представлении нет битов. Он не может создавать объекты.

То, что вы описываете, может быть отправлено в и из. Поэтому он содержит информацию. Поэтому это не пустая пустота.

То, что вы описываете, это просто int, где численное значение игнорируется. Но предлагаемое использование - это плохая практика.

0

void является «необитаемым» типом, то есть нет возможных значений типа void. Поскольку нет возможных значений, для хранения void не требуется свободного места. Поэтому значения void были бы бессмысленными.

Переход назад: C и C++ довольно последовательно распознают void как значение «ничего». Вы можете иметь указатель на ничего и использовать его для переноса значения указателя на что-то вокруг, но вы не можете его разыменовать - void не имеет никакого значения, с которым вы можете что-либо сделать.

Следует также отметить, что void не -это-ничто несет через к делу указатель недействительным: в то время как некоторые компиляторы, такие как GNU позволяют делать арифметические операции над указателями на void* значения, как если бы они были char*, стандарты запрещают арифметику указателей на void* потому что, поскольку void ничего, у него нет значимого размера.

Итак, я думаю, что ответ таков: это было бы бессмысленно.void ничего, и вы ничего не можете хранить в значении.

0

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

Я думаю, что вы можете взглянуть на профсоюзы. Объединение резервирует достаточно места для хранения наибольшего члена профсоюза, а затем в зависимости от того, как вы ссылаетесь на союз, выбирает «подходящее» количество пространства и дает его вам как тип, который вы запрашиваете.

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

0

Если бы был тип данных в пустоте, я думаю, что он не должен представлять ничего и просто проглотить что-либо, что хранится в нем.

вы можете сказать

(void)func1(); 

так почему бы не

void x; 
x = func1(); 

или

void func2() { 
    void x; 
    ... 
    return x; 
} 

и в качестве аргумента функции

int func3(int x, void y, char z); 

void x = func3(1,2); 
x = func3(1,x,2); 

Использование void в выражении является ошибкой

Я вижу, как это используется в некоторых кодировках шаблонов.

+0

Функция void может напрямую возвращать «результат» из другой функции void, и да, *, что * полезно в случае шаблонов. (То есть, ничего не возвращается, это просто разрешено синтаксически.) – UncleBens