2012-01-02 5 views
1

내 문자열 조작에 std :: string 유형을 사용하고 있습니다.C++ : std :: string 개체에서 char * 포인터를 분리 할 수 ​​있습니까?

그러나 원래 std :: string 개체가 삭제 된 후에도 원시 char * 포인터를 유지해야하는 경우가 있습니다 (예, char * 포인터가 HEAP를 참조하므로 결국 처분해야 함).

그러나 원시 포인터를 문자열에서 분리 할 방법이없는 것처럼 보입니까?

아마 다른 문자열 구현을 사용해야합니까?

감사합니다.

편집

사람들은, 복사와 분리 혼동하지 마십시오. 분리의 핵심은 문자열 객체가 기본 버퍼에 대한 소유권을 포기하는 것입니다.

char *ptr = NULL; 
{ 
    std::string s = "Hello world!"; 
    ptr = s.detach(); // May actually allocate memory, if the string is small enough to have been held inside the static buffer found in std::string. 
    assert(s == NULL); 
} 
// at this point s is destroyed 
// ptr continues to point to a valid HEAP memory with the "Hello world!" string in it. 
... 
delete ptr; // need to cleanup 

답변

5

아니요, std::string::c_str()에 의해 반환 된 포인터를 분리 할 수 ​​없습니다.

해결 방법 : 문자열의 읽기 전용 복사본을 만들고 해당 복사본이 적어도 char * 포인터가 필요한만큼 오래 있어야합니다. 그 사본에 c_str()을 사용하면 원하는만큼 유효합니다.

그럴 수 없다면 char*도 해제 할 수 없습니다. 그리고 그 포인터를 RAII 구조로 감싸려고하면 std :: string 부분 만 다시 구현됩니다.

1

사용 c_str()는 C 스타일의 문자열로 문자열을 복사 : 그래서, 문자열이 detach 방법을 가지고 있었다, 그 의미는 다음과 같이 될 것이다. 사용 후 strcpy()

0

필요한 항목에 따라 사용할 수있는 두 가지 항목이 있습니다. string :: c_str()은 문자를 C 문자열로 복사 한 다음 필요한 문자열을 사용할 수 있습니다. std :: data()는 문자열에 대한 포인터를 반환하지만 두 가지 문제가 있습니다. a) C 문자열과 같이 NULL로 종료되지 않으며 b) std :: string이 삭제 될 때 사라집니다. 따라서 원래 개체를 삭제 한 후에도 붙어 있지 않습니다.

+1

원래 개체를 삭제하면'c_str'도 사라집니다. 그리고 C++ 11의 FWIW는'data'와'c_str' 둘 다 내부 버퍼를 가리키는 널 종료 문자열을 반환합니다. –

1

문자열을 새로운 char 배열로 복사 할 수 있습니다.

std::string s = "My string"; 
char *a = new char[s.size()+1]; 
a[s.size()]=0; 
memcpy(a,s.c_str(),s.size()); 
+2

왜 strcpy (s.c_str())가 필요하지 않습니까? –

0

문자열의 소유권을 변경하는 유일한 방법은 누가 특정 부분의 메모리를 소유 하는지를 알아야하기 때문에 복사하는 것입니다. 이렇게하는 가장 간단한 방법은 문자열을 다른 std :: string 변수에 할당하는 것입니다. 소유권이 자주 변경되는 경우 (또는 특정 객체가 소유자인지 여부를 명확히 결정할 수없는 경우) 참조 계산을 지원하는 다른 문자열 구현 (또는 std :: string에 대한 래퍼)을 사용하려는 경우 항상 새로운 메모리를 할당해야합니다.

0

다음과 같이 U 그것을 사용할 수 있습니다

std::string str = "abcd"; 
char* cStr = str.c_str(); 

감사합니다 ...

+0

'str'이 범위를 벗어날 때'cStr'은 어떻게됩니까? 왜냐하면'c_str()'은'char *'포인터를 분리하지 않고 각각의'std :: string'을 버퍼의 소유자로 유지하기 때문에 쓰레기가됩니다. 분리의 핵심은 문자열이 버퍼에 대한 소유권을 포기한다는 것입니다. 미안하지만 대답은 매우 잘못되었습니다. – mark

+0

@mark : 문자열의 소유권을 취할 수 있도록하려면 문제를 해결하십시오. –

+0

항상 가능한 것은 아니므로 제 질문입니다. – mark

4

std::string :이 std:allocator (또는 템플릿 매개 변수)를 통해 할당합니다. 원시 저장소를 분리 할 수 ​​있다고하더라도 std::allocator을 통해 저장소를 해제해야합니다. 물론 RAII 클래스가 올바르게 수행하기를 원할 것입니다.

다행히 이미 표준 라이브러리에는 RAII 클래스가 있습니다. std::string이라고합니다.

따라서 "분리"기능과 가장 가까운 것은 swap입니다. 리소스를 문자열에서 분리하고 나중에 올바르게 해제 할 수있는 형식 (즉, 다른 문자열)으로 저장합니다. C++ 11에서 이동 할당도 그렇게합니다.

std::string raii_for_ptr; 
const char *ptr = NULL; 
{ 
    std::string s = "Hello world!"; 
    raii_for_ptr.swap(s); // or raii_for_ptr = std::move(s) 
    ptr = raii_for_ptr.c_str(); 
    assert(s == ""); 
} 

// no need to cleanup 

당신의 목표는 자신을 위해 다음, 뭔가의 (a) 그 때문에 터무니없는, 그리고 delete를 호출 할 필요를 생성하는 경우 (b)는 표준 라이브러리는 도움이되지 않습니다. 어쨌든 delete이 아닌 delete[]이 필요합니다. 그러나 문자열이 new으로 (직접적으로) 할당되지 않았으므로 메모리를 가져 와서 delete[]으로 (직접) 사용할 수 있다고 생각하는 것은 적절하지 않습니다.

실제 상황에서 일부 기존 API를 delete[]으로 해제 할 버퍼를 전달해야하는 경우라면 미리 복사 할 필요가있는 것처럼 복사본을 가져와야합니다. 기존 API는 free으로 해제 될 버퍼입니다.

관련 문제