Почему присваивать строку указателю безопасно в конструкторе? - PullRequest
0 голосов
/ 08 мая 2018

У меня есть класс: .h

class test {
public:
    int Length;
    char* Name;
    int* ARR;
    test(int l, char* n, int* a);
    test();
};

.cpp

test::test(int l, char* n, int* a){
    Length=l;
    Name=n;
    ARR=a;
}

И main.cpp

#include<iostream>
void InAFunc(test *kio) {
    int foo[3] = { 1,2,3 };
    *kio = test(7, "Hello!", foo);
}
int main() {
    test mmk;
    InAFunc(&mmk);
    std::cout << mmk.Name << mmk.ARR[1];
}

Как я знаю, я могу получить исключение для ARR, потому что переменная foo была освобождена в конце функции InAFunc. Мне нужно сделать новый или malloc для Arr, чтобы избежать этого. Мой вопрос, почему "Привет!" безопасно? Я очень много кодирую в прошлом, но никогда не ошибаюсь. Почему оставить строку в конструкторе без new или malloc - это нормально? Имя переменной в этом классе является указателем.

Ответы [ 4 ]

0 голосов
/ 08 мая 2018

Ваш код имеет неопределенное поведение (что означает сбой не гарантируется!), Но не по той причине, о которой вы думаете.

InAFunc() принимает test объект по значению , поэтому копия входного test объекта создается при вызове InAFunc(). Любые изменения, которые InAFunc() вносит в свой параметр kio, являются локальными для InAFunc() и не отражаются обратно для вызывающей стороны.

Переменная mmk в main() сконструирована по умолчанию, поэтому предположительно mmk.Name и mmk.ARR имеют значение NULL (хотя вы не показали код для этого конструктора), и InAFunc() не будет перезаписывать тот. неопределенное поведение передавать указатель NULL char* на operator<< или индексировать указатель NULL int*.

Возможно, вы хотели InAFunc() вывести новый объект test, который он создает. В этом случае параметр kio необходимо передать по ссылке вместо по значению :

void InAFunc(test &kio)

Теперь переменная mmk в main() получит значения, которые присваивает InAFunc(). mmk.Name и mmk.ARR больше не будут равны NULL.

Теперь вы будете назначать указатель на строковый литерал на mmk.Name, а строковый литерал находится в постоянной доступной только для чтения памяти в течение всего времени жизни процесса, поэтому передача mmk.Name в operator<< будет четко определена и не приведет к сбою.

Однако mmk.ARR действительно будет указывать на массив, локальный для InAFunc() и больше не будет действительным после выхода InAFunc(), как вы и предполагали. Таким образом, вы будете иметь неопределенное поведение при попытке индексирования в mmk.ARR (хотя память, на которую указывает mmk.ARR, вероятно, все равно будет выделена , поэтому код, скорее всего, будет не сбой).

0 голосов
/ 08 мая 2018

Строка «Hello» - это string literal, которая существует на протяжении всей программы. Таким образом, вы всегда можете указать на это, не нарушая указатели. Он не будет уничтожен в конце функции.

0 голосов
/ 08 мая 2018

о, я не понял, в чем проблема. константный строковый литерал находится в области (только для чтения), которая управляется компилятором, он будет бесплатным, пока программа не остановится. Строковые литералы: куда они деваются? .....................................

Тип «hello» - это char * (на самом деле char [6]), а не строка. char * может использоваться как строка из-за неявного преобразования, std :: string имеет конструктор, который принимает char * в качестве параметра. http://en.cppreference.com/w/cpp/string/basic_string/basic_string

Кстати, "kio = test (...)" не может быть скомпилирован.

0 голосов
/ 08 мая 2018

Почему оставить строку в конструкторе без new или malloc - это нормально? Почему присваивать строку указателю безопасно в конструкторе?

В C ++ все является объектами :

  • int - это объект.
  • Строковый литерал - это объект.
  • Указатель тоже является объектом, который может быть назначен.

Таким образом, указатель Name является , указывающим на место, где находится строковый литерал .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...