Programing

문자열 스트림, 문자열 및 char * 변환 혼동

lottogame 2020. 6. 24. 07:55
반응형

문자열 스트림, 문자열 및 char * 변환 혼동


내 질문은 삶의 문자열 stringstream.str().c_str()이 메모리 에서 어디로 반환 되는지, 왜 const char*?에 할당 할 수 없습니까?

이 코드 예제는 내가 할 수있는 것보다 더 잘 설명합니다.

#include <string>
#include <sstream>
#include <iostream>

using namespace std;

int main()
{
    stringstream ss("this is a string\n");

    string str(ss.str());

    const char* cstr1 = str.c_str();

    const char* cstr2 = ss.str().c_str();

    cout << cstr1   // Prints correctly
        << cstr2;   // ERROR, prints out garbage

    system("PAUSE");

    return 0;
}

stringstream.str().c_str()할당 될 수있는 가정은 const char*추적하는 데 시간이 걸리는 버그로 이어졌습니다.

보너스 포인트의 경우, 누가 cout진술을

cout << cstr            // Prints correctly
    << ss.str().c_str() // Prints correctly
    << cstr2;           // Prints correctly (???)

문자열을 올바르게 인쇄합니까?

Visual Studio 2008에서 컴파일 중입니다.


stringstream.str()전체 표현식의 끝에서 파괴 된 임시 문자열 객체를 반환합니다. ( stringstream.str().c_str()) 에서 C 문자열에 대한 포인터를 얻으면 명령문이 끝나는 위치에서 삭제되는 문자열을 가리 킵니다. 그렇기 때문에 코드가 쓰레기를 출력합니다.

임시 문자열 객체를 다른 문자열 객체로 복사하고 C 문자열을 가져올 수 있습니다.

const std::string tmp = stringstream.str();
const char* cstr = tmp.c_str();

임시 문자열을 const변경하면 변경 사항이 다시 할당되어 cstr무효화 될 수 있기 때문에 임시 문자열을 만들었습니다 . 호출 결과를 전혀 저장하지 않고 전체 표현식이 끝날 때까지만 str()사용 하는 것이 더 안전합니다 cstr.

use_c_str( stringstream.str().c_str() );

물론 후자는 쉽지 않을 수 있으며 복사 비용이 너무 비쌀 수 있습니다. 대신 임시를 const참조 에 바인딩하는 것이 가능합니다 . 이는 수명을 참조 수명으로 연장합니다.

{
  const std::string& tmp = stringstream.str();   
  const char* cstr = tmp.c_str();
}

최고의 솔루션 인 IMO. 불행히도 그것은 잘 알려져 있지 않습니다.


당신이하고있는 일은 임시를 만드는 것입니다. 임시는 컴파일러에 의해 결정된 범위에 존재하므로, 어디로 가고 있는지에 대한 요구 사항을 충족시키기에 충분히 길다.

명령문 const char* cstr2 = ss.str().c_str();이 완료 되 자마자 컴파일러는 임시 문자열을 유지할 이유가 없으므로 파기되어 const char *메모리를 비 웁니다.

귀하의 진술 string str(ss.str());은 임시가 로컬 스택에 넣은 string변수 의 생성자에서 사용되며 str예상되는 한 블록의 끝 또는 작성한 함수가 끝날 때까지 유지됩니다. 따라서 const char *를 시도 할 때 within은 여전히 ​​좋은 메모리 cout입니다.


이 줄에서 :

const char* cstr2 = ss.str().c_str();

ss.str() will make a copy of the contents of the stringstream. When you call c_str() on the same line, you'll be referencing legitimate data, but after that line the string will be destroyed, leaving your char* to point to unowned memory.


The std::string object returned by ss.str() is a temporary object that will have a life time limited to the expression. So you cannot assign a pointer to a temporary object without getting trash.

Now, there is one exception: if you use a const reference to get the temporary object, it is legal to use it for a wider life time. For example you should do:

#include <string>
#include <sstream>
#include <iostream>

using namespace std;

int main()
{
    stringstream ss("this is a string\n");

    string str(ss.str());

    const char* cstr1 = str.c_str();

    const std::string& resultstr = ss.str();
    const char* cstr2 = resultstr.c_str();

    cout << cstr1       // Prints correctly
        << cstr2;       // No more error : cstr2 points to resultstr memory that is still alive as we used the const reference to keep it for a time.

    system("PAUSE");

    return 0;
}

That way you get the string for a longer time.

Now, you have to know that there is a kind of optimisation called RVO that say that if the compiler see an initialization via a function call and that function return a temporary, it will not do the copy but just make the assigned value be the temporary. That way you don't need to actually use a reference, it's only if you want to be sure that it will not copy that it's necessary. So doing:

 std::string resultstr = ss.str();
 const char* cstr2 = resultstr.c_str();

would be better and simpler.


The ss.str() temporary is destroyed after initialization of cstr2 is complete. So when you print it with cout, the c-string that was associated with that std::string temporary has long been destoryed, and thus you will be lucky if it crashes and asserts, and not lucky if it prints garbage or does appear to work.

const char* cstr2 = ss.str().c_str();

The C-string where cstr1 points to, however, is associated with a string that still exists at the time you do the cout - so it correctly prints the result.

In the following code, the first cstr is correct (i assume it is cstr1 in the real code?). The second prints the c-string associated with the temporary string object ss.str(). The object is destroyed at the end of evaluating the full-expression in which it appears. The full-expression is the entire cout << ... expression - so while the c-string is output, the associated string object still exists. For cstr2 - it is pure badness that it succeeds. It most possibly internally chooses the same storage location for the new temporary which it already chose for the temporary used to initialize cstr2. It could aswell crash.

cout << cstr            // Prints correctly
    << ss.str().c_str() // Prints correctly
    << cstr2;           // Prints correctly (???)

The return of c_str() will usually just point to the internal string buffer - but that's not a requirement. The string could make up a buffer if its internal implementation is not contiguous for example (that's well possible - but in the next C++ Standard, strings need to be contiguously stored).

In GCC, strings use reference counting and copy-on-write. Thus, you will find that the following holds true (it does, at least on my GCC version)

string a = "hello";
string b(a);
assert(a.c_str() == b.c_str());

The two strings share the same buffer here. At the time you change one of them, the buffer will be copied and each will hold its separate copy. Other string implementations do things different, though.

참고URL : https://stackoverflow.com/questions/1374468/stringstream-string-and-char-conversion-confusion

반응형