programing

stringstream, string 및 char* 변환 혼동

powerit 2023. 8. 11. 22:38
반응형

stringstream, string 및 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()전체 식의 끝에서 삭제된 임시 문자열 개체를 반환합니다.만약 당신이 그것으로부터 C 문자열에 대한 포인터를 얻는다면,stringstream.str().c_str().), 를 참조하십시오.그래서 코드가 쓰레기를 출력하는 겁니다.

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

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

로 임시 ▁the다니▁note▁made▁temporary를 만들었습니다.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());▁theor의 에서 사용되는 것을 합니다.stringstr사용자가 로컬 스택에 추가하고 블록이 끝날 때까지 또는 사용자가 작성한 기능을 사용할 수 있습니다. 그므로러로.const char *당신이 그것을 시도할 때 여전히 좋은 기억입니다.cout.

다음 줄에서:

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

ss.str()문자열 스트림의 내용을 복사합니다.전화할 때c_str()동일한 라인에서, 당신은 합법적인 데이터를 참조할 것이지만, 그 라인 이후에 문자열이 파괴되어 당신의 것을 남기게 될 것입니다.char*소유하지 않은 기억을 가리킵니다.

ss.str()에서 반환된 std::string 개체는 식으로 제한된 수명을 갖는 임시 개체입니다.따라서 휴지통을 가져오지 않고는 임시 개체에 포인터를 할당할 수 없습니다.

한 가지 예외가 있습니다. 임시 개체를 얻기 위해 항상 참조를 사용하는 경우 더 넓은 수명 동안 사용하는 것이 합법적입니다.예를 들어 다음을 수행해야 합니다.

#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;
}

그렇게 하면 더 오랜 시간 동안 끈을 얻을 수 있습니다.

RVO라는 최적화 방법이 있다는 것을 알아야 합니다. 컴파일러가 함수 호출을 통해 초기화를 보고 해당 함수가 임시를 반환하면 복사를 수행하지 않고 할당된 값을 임시로 만듭니다.이렇게 하면 참조를 실제로 사용할 필요가 없습니다. 복사할 필요가 없는지 확인하려는 경우에만 참조가 필요합니다.실행 방법:

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

더 낫고 더 간단할 것입니다.

ss.str()의 초기화 후 임시가 삭제됩니다.cstr2완료되었습니다.그래서 당신이 그것을 인쇄할 때.cout 것과관련된그 c-string과 .std::string임시는 오래 전에 파괴되었으므로 충돌하고 주장하면 운이 좋고, 쓰레기를 인쇄하거나 작동하는 것처럼 보이면 운이 좋지 않습니다.

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

위열이 인 C 입니다.cstr1그러나 포인트는 당신이 할 때 여전히 존재하는 문자열과 연관되어 있습니다.cout결과를 올바르게 출력합니다.

다음 코드에서 첫 번째는cstr맞습니다(나는 그렇다고 가정합니다).cstr1실제 코드로?). 개체인 "과 관련된 c-string을 출력합니다.ss.str()개체가 표시되는 전체 표현식을 평가하는 마지막에 개체가 삭제됩니다.전체 표현식은 전체입니다.cout << ...expression - c-string이 출력되는 동안 연결된 문자열 개체가 여전히 존재합니다.cstr2그것이 성공하는 것은 순전히 나쁜 것입니다.된 임시로 선택한 새 의 저장 한 저장 .cstr2추락할 수도 있습니다.

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

c_str()일반적으로 내부 문자열 버퍼만 가리킵니다. 하지만 이는 요구 사항이 아닙니다.예를 들어 내부 구현이 연속적이지 않으면 문자열이 버퍼를 구성할 수 있습니다(가능성이 높지만 다음 C++ 표준에서는 문자열을 연속적으로 저장해야 합니다).

GCC에서 문자열은 참조 카운트와 쓰기 시 복사를 사용합니다.따라서 다음이 사실이라는 것을 알게 될 것입니다(적어도 내 GCC 버전에서는 그렇습니다).

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

두 문자열은 여기서 동일한 버퍼를 공유합니다.이 중 하나를 변경하면 버퍼가 복사되고 각 버퍼는 별도의 복사본을 보유합니다.그러나 다른 문자열 구현은 다른 작업을 수행합니다.

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

반응형