Что возвращает новый [size_t] + 1

Следующий пример кода из книги "C ++ von A bis Z" (второе издание, перевод: C ++ от A до Z) на странице 364. Образец неверен.

// overload operator +=
#include <iostream>
#include <cstring>
using namespace std;

class String {
private:
    char* buffer;
    unsigned int len;

public:
    String(const char* s="") {
        // cout << "Constructor: " << s << "\n";
        len = strlen(s);
        buffer = new char [len+1];
        strcpy(buffer, s);
    }
    ~String() {
        // cout << "Destructor: " << buffer << "\n";
        delete [] buffer;
    }
    String(const String& s) {
        // cout << "Copy_Constructor: " << s.get_buffer() << "\n";
        len = s.len;
        buffer = new char [len+1];
        strcpy(buffer, s.buffer);
    }
    char* get_buffer() const {
        return buffer;
    }

    // returning a reference is more efficent
    // String& operater+=(const String& str1)
    String operator+=(const String& str1) {
        // cout << "Assignment_Operator +=: " << str1.get_buffer() << "\n";
        String tmp(*this);
        delete [] buffer;
        len = tmp.len + str1.len;
        // invalid pointer
        // buffer = new char[len+1];
        buffer = new char [len]+1;
        strcpy(buffer, tmp.buffer);
        strcat(buffer, str1.buffer);
        // wrong return_type
        // return *this;
        return buffer;
    }
};

int main(void) {
    String string1("Adam");
    String string2("Eva");
    string1+=" und ";
    string1.operator+=(string2);
    cout << string1.get_buffer() << "\n";
    return 0;
}

Строки с комментариями - мои «исправления». Теперь я хочу знать, что делает "new char [len] +1"? Думаю следующее:

  • он выделяет sizeof (char) * len память из кучи
  • и возвращает НЕПРАВИЛЬНЫЙ адрес указателю * буфер
  • но каков неправильный адрес: «первый адрес новой памяти в куче + 1» или «первый адрес новой памяти в куче + sizeof (char) * 1)?

Что случается? Спасибо

// редактировать Всем спасибо! Ты мне помог! Я просто хотел знать, что вернет это заявление.

new char [len]+1;

Сама строчка, конечно же, опечатка автора книги.


person Peter    schedule 09.12.2011    source источник
comment
Чем отличается ваш третий пункт? sizeof(char) == 1 по определению.   -  person Kerrek SB    schedule 09.12.2011
comment
Кроме того, кому наплевать - если вы занимаетесь C ++, забудьте о char* и strcpy и необработанных массивах.   -  person Kerrek SB    schedule 09.12.2011
comment
Думаю, вы правы во всех своих предположениях. Возвращаемый адрес - это первый адрес новой памяти в куче + sizeof (char) * 1, но в любом случае это не имеет смысла для этого кода.   -  person Lyth    schedule 09.12.2011
comment
Это обряд посвящения или что-то в этом роде, написание собственного строкового класса. Не могу сказать, что поняла, учитывая std::string, но да.   -  person cHao    schedule 09.12.2011
comment
@KerrekSB: все это очень хорошо говорит новичкам забыть о char*, но вы уверены, что хотите, чтобы они не понимали, почему "hello, " + "world" не работает? В конечном итоге они спросят о SO, и их будут упрекать за то, что они не знают о char*. Реализация строкового класса, возможно, больше, чем им строго нужно, но я бы предпочел, чтобы они примерно знали, как он работает.   -  person Steve Jessop    schedule 09.12.2011
comment
@cHao: это потому, что одна из интересных вещей в дизайне C ++ заключается в том, что вы предполагалось иметь возможность реализовать этот и аналогичные классы в пользовательском режиме (под этим я подразумеваю отсутствие необходимости в специальном компиляторе / поддержка времени выполнения или оптимизированный код, написанный на других языках) с не большими накладными расходами, чем стандартная реализация. Конечно, не многие люди на самом деле используют этот аспект C ++ в своей повседневной жизни, но если вы собираетесь изучать C ++, вы можете также изучить его предполагаемые основные функции. Проблема в том, что если вы сделаете это в первую очередь, вы можете подумать, что весь код C ++ низкоуровневый.   -  person Steve Jessop    schedule 09.12.2011
comment
@Kerrek SB или вообще всем, кто пишет, вам не нужна особенность языка $ foobar: не воспринимайте это как личную критику! Это образец для изучения C ++, а для использования C ++ каждый должен знать, как работают cstrings и указатели. Также пользователь должен знать немного о том, как работает строка Template-Class из C ++. C ++ - это надмножество C, поэтому хороший программист C ++ должен уметь читать и использовать C. И, наконец, обучение должно начинаться с низкоуровневого материала, а не с высокого уровня. Вот почему каждая хорошая книга начинается с Hello world! а не с Quicksort :-) Спасибо   -  person Peter    schedule 09.12.2011
comment
@Peter: обучение должно начинаться с мелочей, а не с высокого, я вообще не думаю, что это правда. Причина, по которой книги начинаются с hello world, а не с быстрой сортировки, заключается в том, что они должны начинаться с simple, а не с low-level. И в любом случае архетипичный C ++ привет, мир - это верхний уровень std::cout << "hello, world\n";, а не нижний уровень std::puts("hello, world");. Часто высокий уровень проще и легче для понимания, и вы работаете с низким уровнем. Возьмем, к примеру, химию: вы не изучаете уравнения Шредингера для электронов, прежде чем изучите валентность.   -  person Steve Jessop    schedule 09.12.2011
comment
Хе-хе! Нам не нужно знать все, мы не можем знать всего! Знание основ Ассемблера для написания C / C ++ не важно. Важно знать основы char, cstring и string в C / C ++. Или, другими словами, знание того, что атом важен сегодня, знание того, что такое кварк (в настоящее время), не важно. Я очень часто видел комментарии вроде «Не учись этому, не пытайся понять, используйте высокоуровневые вещи, это менее сложно». Это неправильный путь. Смотрите - Когда сучья ломаются (Звездный путь: Следующее поколение)   -  person Peter    schedule 09.12.2011


Ответы (6)


Давайте разберемся:

new char[len];

возвращает указатель на массив char.

new char[len] + 1;

возвращает следующий адрес в памяти.

По сути, это отключение первого символа.

РЕДАКТИРОВАТЬ: Как уже упоминали другие, это, скорее всего, опечатка, это должно быть new char[len+1]. Я просто объясняю, что делает код, но вам следует использовать арифметику указателей, только если вы действительно знаете, что делаете. Как указал Чао, попытка удалить возвращенный указатель будет UB. Вы также получите UB, если len == 1, и попытаетесь работать с возвращенным указателем.

person Luchian Grigore    schedule 09.12.2011
comment
И, конечно же, установка buffer на указатель, который вызывает UB, когда вы собираетесь удалить его. - person cHao; 09.12.2011
comment
Следует уточнить, что следующий адрес в памяти означает текущий адрес + sizeof (char), а не текущий адрес + 1 (хотя это то же самое в случае char), поскольку это был фактический вопрос. - person sepp2k; 09.12.2011

Если вы добавите целое число i к T*, это добавит sizeof(T) * i к указателю. В этом случае, поскольку new char[len] возвращает char*, + 1 действительно добавит к нему sizeof(char) * 1.

person sepp2k    schedule 09.12.2011

new Type[size] + 1 выделит массив размером size и выдаст адрес элемента с индексом 1 - второго элемента. Ничего особенного, просто арифметика с указателями. new[] даст адрес элемента с индексом 0, а размер +1 выполняется по этому адресу, он дает адрес элемента с индексом 1.

person sharptooth    schedule 09.12.2011

Просто возвращает указатель на второй элемент массива =) Прочтите про указатели C;)

person shybovycha    schedule 09.12.2011

+sizeof(char)*1, но я не понял, зачем вы это сделали.

person Michael Krelin - hacker    schedule 09.12.2011

Я думаю, что это опечатка, и это должно быть new char [len+1]. +1 предназначен для символа терминатора строки, который должен существовать.

person Some programmer dude    schedule 09.12.2011
comment
Как я это читал, OP полностью осознает, что строка неправильная и как ее исправить (если вы посмотрите на комментарии, он уже исправил это). Он просто спрашивает, что сделает не та линия. - person sepp2k; 09.12.2011