char * vs std :: string in C ++ [닫힘]


81

C ++에서 s 배열을 관리하기 위해 std::string언제 사용해야 하며 언제 사용해야 합니까?char*char

char*성능 (속도)이 중요하고 메모리 관리로 인해 위험한 비즈니스를 기꺼이 받아 들일 경우 사용해야하는 것 같습니다 .

고려해야 할 다른 시나리오가 있습니까?

답변:


56

복사를 피하기 위해 큰 경우 참조로 std :: strings 또는 인스턴스에 대한 포인터를 전달할 수 있으므로 char 포인터를 사용하여 실제 이점을 보지 못합니다.

실제 텍스트 인 모든 것에 std :: string / wstring을 사용합니다. char *하지만 다른 유형의 데이터에 유용하며 원하는대로 할당이 해제 될 수 있습니다. 그렇지 않으면 std :: vector가 갈 길입니다.

이 모든 것에는 예외가있을 수 있습니다.


8
두 가지 전에 성능 차이가 있습니까?
vtd-xml-author

3
@ vtd-xml-author : 아마도 일부. 스트레이트 char *는 오버 헤드가 거의 없습니다. 정확히 어떤 오버 헤드 std::string가 내가 알지 못하며 구현에 따라 달라질 수 있습니다. 나는 베어 char 포인터보다 오버 헤드가 훨씬 더 클 것이라고 거의 기대하지 않는다. 나는 표준 사본을 소유하고 있지 않기 때문에 표준에 의해 만들어진 어떤 보증도 자세히 설명 할 수 없습니다. 성능 차이는 수행 할 작업에 따라 달라질 수 있습니다. std::string::size문자 데이터 옆에 크기를 저장할 수 있으므로 strlen.
Skurmedel

2
텍스트가 아닌 데이터에 std :: string을 사용하지 않는 이유는 무엇입니까? null로 끝나지 않으므로 원하는 것을 저장할 수 있어야합니다.
Casey Rodarmor 2012 년

1
@rodarmor 원하는 것은 무엇이든 저장할 있지만 문자열은 null로 끝나는 문자열 용으로 설계 되었기 때문에 터치 위험이 있습니다. 바이너리 안전 연산 만 사용하도록주의해야합니다 (예 : append(const string&)append(const char*, size_t)대신 operator+=().
boycy

6
확실합니까? 많은 작업이 char *가 null로 끝나는 문자열이라고 가정한다는 것을 알고 있지만 std :: string에 null이 포함되어 있지 않다고 가정하는 것은 생각할 수 없습니다.
Casey Rodarmor 2012 년

57

내 관점은 :

  • "C"코드를 호출하지 않으면 char *를 사용하지 마십시오.
  • 항상 std :: string 사용 : 더 쉽고, 더 친숙하며, 최적화되고, 표준이며, 버그가 발생하지 않도록 방지하고, 확인되고 작동하는 것으로 입증되었습니다.

13

원시 문자열 사용

예, 때로는 정말 할 수 있습니다. const char *, 스택에 할당 된 char 배열 및 문자열 리터럴을 사용할 때 메모리 할당이 전혀없는 방식으로 수행 할 수 있습니다.

이러한 코드를 작성하려면 문자열이나 벡터를 사용하는 것보다 더 많은 생각과주의가 필요하지만 적절한 기술을 사용하면 수행 할 수 있습니다. 적절한 기술을 사용하면 코드가 안전 할 수 있지만 char []로 복사 할 때 복사되는 문자열의 길이에 대한 보증이 있는지 항상 확인해야합니다. 아니면 크기가 큰 문자열을 정상적으로 확인하고 처리해야합니다. 그렇게하지 않으면 strcpy 기능 군이 안전하지 않다는 평판을 얻었습니다.

템플릿이 안전한 문자 버퍼 작성을 돕는 방법

char [] 버퍼의 안전성과 관련하여 템플릿은 버퍼 크기를 처리하기위한 캡슐화를 생성 할 수 있으므로 도움이 될 수 있습니다. 이와 같은 템플릿은 Microsoft에서 strcpy를 안전하게 대체하기 위해 구현합니다. 여기 예제는 내 코드에서 추출되었으며 실제 코드에는 더 많은 메서드가 있지만 기본 아이디어를 전달하기에 충분해야합니다.

template <int Size>
class BString
{
  char _data[Size];

  public:
  BString()
  {
    _data[0]=0;
    // note: last character will always stay zero
    // if not, overflow occurred
    // all constructors should contain last element initialization
    // so that it can be verified during destruction
    _data[Size-1]=0;
  }
  const BString &operator = (const char *src)
  {
    strncpy(_data,src,Size-1);
    return *this;
  }

  operator const char *() const {return _data;}
};

//! overloads that make conversion of C code easier 
template <int Size>
inline const BString<Size> & strcpy(BString<Size> &dst, const char *src)
{
  return dst = src;
}

1
+1 for "const char *, 스택에 할당 된 char 배열 및 문자열 리터럴을 사용할 때 메모리 할당이 전혀없는 방식으로 수행 할 수 있습니다." 사람들은 스택 "할당"이 힙보다 훨씬 빠르다는 사실을 잊습니다.
NoSenseEtAl

char*문자열이 항상 스택에있는 것은 아닙니다. char *str = (char*)malloc(1024); str[1024] = 0;
Cole Johnson

@ColeJohnson 나는 주장하는 것이 아니라 문자열을 스택 할당하려면 std :: string이 아닌 문자열 리터럴과 함께 const char *를 사용해야 함을 의미합니다.
Suma

9

당신이 사용해야 하나의 기회 char*가 아니라는 std::string정적 문자열 상수를 필요로 할 때입니다. 그 이유는 모듈이 정적 변수를 초기화하는 순서에 대한 제어 권한이 없으며 다른 모듈의 다른 전역 개체가 초기화되기 전에 문자열을 참조 할 수 있기 때문입니다. http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Static_and_Global_Variables

std::string 장점 :

  • 메모리를 관리합니다 (문자열이 커질 수 있으며 구현시 더 큰 버퍼를 할당합니다)
  • 높은 수준의 프로그래밍 인터페이스는 나머지 STL과 잘 작동합니다.

std::string단점 :-두 개의 개별 STL 문자열 인스턴스는 동일한 기본 버퍼를 공유 할 수 없습니다. 따라서 값으로 전달하면 항상 새 사본을 얻습니다. -약간의 성능 저하가 있지만 귀하의 요구 사항이 특별하지 않으면 무시할 만하다고 말하고 싶습니다.


실제로 STL 구현은 종종 std :: string에 대한 copy-on-write 의미 체계를 구현하므로 값으로 전달하는 데 비용이 많이 들지 않습니다. 그럼에도 불구하고 그것에 의존하지 않는 것이 더 낫고 일반적으로 어쨌든 상수에 대한 참조를 전달하는 것이 좋습니다.

1
일부 std :: string 구현은 COW 구현을 포기했습니다. 또한 표준과 호환되는 (POSIX) 스레드 안전 클래스를 제공하는 것만 큼 사소하지 않습니다. 참조 groups.google.fr/group/ifi.test.boa/browse_frm/thread/... 또는 groups.google.fr/group/comp.programming.threads/browse_frm/...
루크 Hermitte

8

char*다음과 같은 경우 에 사용하는 것을 고려해야합니다 .

  • 이 배열은 매개 변수로 전달됩니다.
  • 어레이의 최대 크기를 미리 알고 있습니다 (알거나 부과).
  • 이 배열에서는 어떤 변환도 수행하지 않습니다.

실제로 C ++에서는 char*옵션, 파일 이름 등으로 고정 된 작은 단어에 자주 사용됩니다.


3
배열은 전달되지 않으며 배열에 대한 포인터입니다. 이것이 바로 포인터입니다. 객체에 대한 포인터입니다.
Cole Johnson

5

C ++ std :: string을 사용하는 경우 :

  • 문자열은 전반적으로 char *보다 안전합니다. 일반적으로 char *로 작업을 수행 할 때 문제가 올바른지 확인해야합니다. 문자열 클래스에서이 모든 작업이 수행됩니다.
  • 일반적으로 char *를 사용할 때 할당 한 메모리를 해제해야하며, 파괴 될 때 내부 버퍼를 해제하므로 string으로이를 수행 할 필요가 없습니다.
  • 문자열은 C ++ stringstream과 잘 작동하며 형식화 된 IO는 매우 쉽습니다.

char *를 사용하는 경우

  • char *를 사용하면 장면 "뒤에서"일어나는 일을 더 잘 제어 할 수 있습니다. 즉, 필요한 경우 성능을 조정할 수 있습니다.

3

라이브러리를 작성하는 경우 (const) char *를 매개 변수로 사용하십시오. std :: string 구현은 컴파일러마다 다릅니다.


C ++로 라이브러리를 작성하는 경우 std :: string의 레이아웃 만 걱정할 필요가 없습니다. 두 구현 사이에는 잠재적 인 비 호환성 호스트가 있습니다. 소스에서 사용 가능하거나 사용중인 정확한 컴파일러 용으로 컴파일 된 경우에만 C ++의 라이브러리를 사용하십시오. C 라이브러리는 일반적으로 이식성이 더 좋지만이 경우 std :: string이 없습니다.
David Thornley

std :: string이 유일한 문제는 아니지만 "소스에서 사용할 수 있거나 사용중인 정확한 컴파일러에 대해 컴파일 된 경우에만 C ++에서 라이브러리를 사용하십시오"라는 결론을 내리기에는 너무 많은 것입니다. 다른 컴파일러 (예 : COM)에서 잘 작동하는 구성 요소 시스템이 있으며 내부적으로 C ++ (예 : Win32 API)로 작성된 라이브러리에 C 인터페이스를 노출 할 수 있습니다.
Nemanja Trifunovic

2

C 라이브러리를 사용하려면 C- 문자열을 처리해야합니다. API를 C에 노출하려는 경우에도 동일하게 적용됩니다.


2

std :: string (예 : 예 find) 에 대한 대부분의 작업 은 가능한 한 최적화 될 것으로 예상 할 수 있으므로 최소한 순수한 C 대응만큼 수행 할 가능성이 높습니다.

std :: string 반복자가 기본 char 배열의 포인터에 자주 매핑된다는 점도 주목할 가치가 있습니다. 따라서 반복자 위에서 고안 한 모든 알고리즘은 성능 측면에서 char * 위에있는 동일한 알고리즘과 본질적으로 동일합니다.

주의해야 할 사항은 다음과 같습니다. operator[] . 대부분의 STL 구현은 경계 검사를 수행하지 않으며이를 기본 문자 배열에서 동일한 작업으로 변환해야합니다. AFAIK STLPort는 선택적으로 경계 검사를 수행 할 수 있으며,이 지점에서이 연산자는 약간 느립니다.

그렇다면 std :: string을 사용하면 무엇을 얻을 수 있습니까? 수동 메모리 관리에서 벗어날 수 있습니다. 배열 크기를 조정하는 것이 더 쉬워지며 일반적으로 메모리 확보에 대해 덜 생각해야합니다.

문자열의 크기를 조정할 때 성능이 걱정된다면 reserve유용 할 수 있는 함수가 있습니다.


1

텍스트 등에서 문자 배열을 사용하는 경우 std :: string 더 유연하고 사용하기 쉽습니다. 데이터 저장과 같은 다른 용도로 사용한다면? 배열 사용 (벡터 선호)


1

성능이 중요한 경우에도 사용하는 것이 좋습니다 vector<char>. 사전에 메모리 할당 (reserve () 메서드)을 허용하고 메모리 누수를 방지하는 데 도움이됩니다. vector :: operator []를 사용하면 오버 헤드가 발생하지만 항상 버퍼의 주소를 추출하고 char * 인 것처럼 정확히 인덱싱 할 수 있습니다.


그러나 일종의 일반적인 문자열 기능을 사용하고 저장소에 대한 정책을 지정하는 옵션 만 있으면 좋을 것입니다. 그것에 대해서는 내 대답의 링크를 참조하십시오.
Anonymous

사실이 아닙니다. 벡터가 연속적인 메모리 공간에 할당 될 것이라고 생각한다면, 재 할당 (벡터 크기 증가)은 이전 청크의 복사본을 의미하므로 전혀 효율적이지 않습니다.
Jérôme

나는 당신이 문자열 대신 char * 대신 벡터를 사용하기 때문에 귀하의 응답을 이해하지 못했습니다.이 경우 동의합니다.
Jérôme

operator [] 사용에 오버 헤드가 없어야합니다. 예를 들어, stackoverflow.com/questions/381621/…을
Luc Hermitte

-1

AFAIK 내부적으로 대부분의 std :: string은 문자열이 참조로 전달되지 않은 경우에도 오버 헤드를 피하기 위해 쓰기시 복사, 참조 계산 시맨틱을 구현합니다.


5
쓰기 중 복사가 다중 스레드 환경에서 심각한 확장 성 문제를 일으키기 때문에 이것은 더 이상 사실이 아닙니다.
수마

GCC의 STL 구현은 적어도 사실입니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.