Внедрение против указателя во вложенных строковых структурах

При разработке структур, содержащих текстовые данные, я использовал два основных подхода, показанных ниже:

typedef struct {
    STRING address1;
    STRING address2;
    STRING city;
    STRING state;
    STRING zip;
} ADDRESS;

typedef struct {
    STRING* address1;
    STRING* address2;
    STRING* city;
    STRING* state;
    STRING* zip;
} ADDRESS;

где STRING - это тип хранения строк переменной длины. Преимущество версии указателя состоит в том, что я могу хранить NULL, указывая, что данные отсутствуют. Например, адрес2 может быть не предоставлен для некоторых адресов. В типе со встроенными STRING я должен использовать "пустую" строку, то есть ту, которая имеет длину 0.

С указателями есть (возможно) больше бремени кода, потому что я должен проверять каждый элемент на NULL перед использованием. Однако преимущество не так велико, потому что обычно нужно проверять и встроенную версию. Например, если я печатаю адрес, я должен проверить строку нулевой длины и пропустить эту строку. С помощью указателей пользователь может фактически указать, что он хочет "пустое" значение вместо отсутствующего значения, хотя использование этого трудно увидеть.

При создании или освобождении структуры указатели добавляют ряд дополнительных шагов. Мой инстинкт состоит в том, чтобы стандартизировать встроенный стиль, чтобы сохранить эти шаги, но я обеспокоен тем, что может быть скрытая ошибка. Это необоснованный страх, или я должен использовать указатели по какой-то веской причине?

Обратите внимание, что использование памяти является проблемой, но это довольно незначительно. Версия указателя занимает немного больше памяти, потому что я храню указатели на структуры в дополнение к структурам. Но каждая строковая структура занимает в среднем около 40 байт, поэтому, если я храню 4-байтовые указатели, то версия указателя стоит, возможно, на 10% больше памяти, что неважно. Наличие нулевых указателей возможно не экономит значительную память, потому что большинство полей заполнены.

Вопрос по поводу АДРЕСА НЕ СТРОНЯ

Некоторые из респондентов, кажется, смущены и думают, что я спрашиваю о глобальных компромиссах, например, как минимизировать мою общую работу. Это не относится к делу. Я спрашиваю о том, как спроектировать АДРЕС, а не STRING. Члены адреса могут иметь фиксированные массивы, а в других случаях - нет. Для целей моего вопроса, я не беспокоюсь о последствиях для контейнера.

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

Если вы не понимаете вопрос, пожалуйста, прочитайте предварительный ответ, который я написал сам ниже (после некоторой дополнительной мысли), чтобы увидеть вид ответа, который я ищу.

3 ответа

Компромиссы по использованию памяти и сокращению malloc

Похоже, компромисс вокруг двух вопросов: 1) Насколько драгоценна память? и 2) Имеет ли значение, что для строк выделяется фиксированный объем памяти, ограничивая длины, которые должны храниться в каждом поле?

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

Одна проблема со встроенным стилем заключается в том, что STRING должен быть определен как что-то вроде char[MAX_CHAR + 1] где MAX_CHAR пессимистическая максимальная длина для данных полей. Стиль указателя позволяет выделить правильный объем памяти. Недостатком, как вы упоминаете, является гораздо более высокая когнитивная нагрузка на управление вашей структурой.

Я рассматривал это более глубоко, и я думаю, что в большинстве случаев указатели необходимы, потому что важно различать пустое и пропущенное. Причина этого заключается в том, что недостающие данные необходимы, когда ввод неверен, поврежден или пропущен. Например, давайте представим, что при чтении из файла файл поврежден, поэтому такое поле, как почтовый индекс, не читается. В этом случае данные "отсутствуют", и указатель должен быть NULL. С другой стороны, давайте представим, что в этом месте нет почтового индекса, тогда оно "пустое". Таким образом, NULL означает, что пользователь еще не предоставил информацию, но пусто означает, что пользователь предоставил информацию, и нет ни одного из рассматриваемых типов.

Итак, чтобы дополнительно проиллюстрировать важность использования указателя, представьте, что сложная структура заполняется во времени различными асинхронными шагами. Здесь нам нужно знать, какие поля были прочитаны, а какие нет. Если мы не используем указатели (или не добавляем дополнительные метаданные), у нас нет возможности определить разницу между полем, на которое был получен ответ, и полем, для которого ответ "нет". Представьте себе систему, запрашивающую у пользователя "что такое почтовый индекс?". Пользователь говорит: "У этого места нет почтового индекса". Затем через 5 минут система снова спрашивает: "что такое почтовый индекс?". Этот вариант использования дает понять, что в большинстве случаев нам нужны указатели.

В этом свете единственная ситуация, в которой я должен использовать встроенные структуры, - это когда структура контейнера гарантированно будет иметь полный набор данных при каждом ее создании.

Другие вопросы по тегам