2010-10-22 3 views
6

Где указатель, возвращаемый вызовом строки :: c_str(), указывает на? В следующем фрагменте кода я думал, что дам ошибку сегментации, но он дает мне правильный результат. Если указатель, возвращаемый строкой :: c_str(), указывает на внутреннее местоположение внутри строкового объекта, тогда, когда функция возвращается и объект-деструктор объекта вызывается, я должен получить недопустимый доступ к памяти.string :: c_str query

#include <iostream> 
#include <string> 
using namespace std; 

const char* func() 
{ 
    string str("test"); 
    return str.c_str(); 
} 

int main() 
{ 
    const char* p = func(); 
    cout << p << endl; 
    return 0; 
} 

Output: test 
Compiler: g++ 4.3.3 
Platform: ubuntu 2.6.28-19 

ответ

13

Где указатель, возвращаемый вызовом string::c_str() точку?

Он указывает на место в памяти, где находится строка с нулевым завершением, содержащая содержимое std::string.

Указатель действителен до изменения или уничтожения std::string. Это также потенциально недействительно, если вы снова вызываете c_str() или data().

В целом, ваша самая безопасная ставка заключается в том, чтобы принять указатель, полученный от c_str(), в следующий раз, когда вы что-то сделаете, что-то делает с объектом std::string.

Я должен получить недопустимый доступ к памяти.

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

+0

AFAICT, указатель, возвращаемый 'c_str()', действителен до следующего вызова функции non-const. Поскольку 'c_str()' и 'data()' являются и самими константами, они не могут аннулировать ранее возвращенные указатели. – MSalters

+1

@MSalters: Я тоже так думал, но: «Ссылки, указатели и итераторы, ссылающиеся на элементы последовательности« basic_string », могут быть аннулированы следующими применениями этого объекта« basic_string »: ... Вызов' data () 'и' c_str() 'функции-члены" (C++ 03 21.3/5). Я бы рассмотрел 'c_str()' как возвращающий указатель на элемент в строке, чтобы указатель _could_ был недействителен другим вызовом 'c_str()'. Я мог ошибаться. –

+0

Я думаю, что идея в том, что basic_string может реализовать c_str(), добавив '\ 0' в свой внутренний буфер и вернув указатель на этот добавленный буфер. Такая реализация редко хранит '\ 0' и никогда не хранит две копии.Этот текст, который вы указываете, позволяет это - не указано, возвращает ли 'c_str' указатель на элементы или указатель на копию этих элементов. – MSalters

2

Что вы ожидаете от печати?

#include <iostream> 
#include <string> 

int main() 
{ 
    int* test = new int[20]; 
    test[15] = 5; 
    std::cout << test[15] << "\n"; 
    delete[] test; 
    std::cout << test[15] << "\n"; 
    return 0; 
} 

В режиме выпуска на VS 2010, я получаю этот результат:

освобождаться память не обязательно бросать исключение при попытке доступа к нему , Значение не обязательно должно быть переписано. (Интересно, что если я изменю режим компиляции в режим отладки, компилятор перезапишет значение -572662307).

Что происходит, когда вы пытаетесь получить к нему доступ, не определено стандартом. Это означает, что компилятор может делать все, что угодно, или делать ничего не делать. (Или сбой вашей программы или взорвать вселенную ...)

+0

Отличная иллюстрация .... – Tanuj