Nice programing

""+ C ++의 무언가

nicepro 2020. 12. 7. 20:40
반응형

""+ C ++의 무언가


내 코드에서 정말 이상한 일이 일어나고 있습니다. "여기"라는 레이블이 붙은 부분까지 추적했다고 생각합니다 (물론 코드는 간단합니다).

std::string func() {
    char c;
    // Do stuff that will assign to c
    return "" + c; // Here
}

cout이 함수의 결과를 시도하면 모든 종류의 일이 발생 합니다. 나는 심지어 기본 C ++ 문서의 일부와 많은 세분화 오류 를 얻을 수 있다고 생각 합니다. 이것이 C ++에서 작동하지 않는다는 것은 분명 하지만 (지금 stringstream까지 변환을 사용 하는 데 의지했습니다 string) 그 이유를 알고 싶습니다. 꽤 오랫동안 많은 C #을 사용하고 C ++를 사용하지 않은 후, 이로 인해 많은 고통이 발생했습니다.


  • ""문자열 리터럴입니다. 그것들은 Nconst char 의 타입 배열을 가지고 있습니다 . 이 특정 문자열 리터럴은 1const char배열이며 , 하나의 요소가 널 종료 자입니다.

  • 배열은 포인터가 필요한 표현식에서와 같이 첫 번째 요소에 대한 포인터로 쉽게 붕괴됩니다.

  • lhs + rhs배열 lhs과 정수에 대해 정의되지 않았습니다 rhs. 그러나 일반적인 포인터 산술로 포인터에 대해서는 lhs로, 정수는 rhs로 정의합니다.

  • char C ++ 핵심 언어의 정수 데이터 유형입니다 (즉, 정수로 처리됨).

따라서 ==> 문자열 리터럴 +문자포인터 +정수 로 해석됩니다 .

표현식 "" + c은 대략 다음과 같습니다.

static char const lit[1] = {'\0'};
char const* p = &lit[0];
p + c // "" + c is roughly equivalent to this expression

당신은을 반환합니다 std::string. 표현식 "" + c은에 대한 포인터를const char 생성합니다 . 생성자 std::string즉 기대 const char*가 널 종료 문자 배열 포인터 것으로 기대한다.

이면 c != 0표현식 "" + c이 정의되지 않은 동작으로 이어집니다.

  • 의 경우 c > 1포인터 산술은 정의되지 않은 동작을 생성합니다. 포인터 산술은 배열에서만 정의되며 결과가 동일한 배열의 요소 인 경우에만 정의됩니다.

  • char서명 된 경우 c < 0동일한 이유로 정의되지 않은 동작을 생성합니다.

  • 의 경우 c == 1포인터 산술 정의되지 않은 동작을 생성 하지 않습니다 . 특별한 경우입니다. 배열의 마지막 요소를 지나서 하나의 요소를 가리키는 것은 허용됩니다 (하지만 가리키는 것을 사용하는 것은 허용되지 않습니다). std::string여기에서 호출 생성자는 인수가 유효한 배열 (및 null로 끝나는 문자열)에 대한 포인터 여야하므로 여전히 정의되지 않은 동작으로 이어집니다 . 마지막 마지막 요소는 배열 자체의 일부가 아닙니다. 이 요건을 위반하면 UB로 이어집니다.


아마도 이제 발생하는 것은의 생성자 std::string가 다음과 같은 배열에서 (첫 번째) 문자를 검색하여 전달한 null로 끝나는 문자열의 크기를 결정하려고 시도하는 것입니다 '\0'.

string(char const* p)
{
    // simplified
    char const* end = p;
    while(*end != '\0') ++end;
    //...
}

이로 인해 액세스 위반이 발생하거나 생성 된 문자열에 "가비지"가 포함됩니다. 컴파일러가이 Undefined Behavior가 절대 발생하지 않는다고 가정하고 이상한 동작을 초래하는 재미있는 최적화를 수행 할 수도 있습니다.


그건 그렇고, clang ++ 3.5 는이 스 니펫에 대해 멋진 경고 를 내 보냅니다.

경고 : 문자열에 'char'를 추가하면 [-Wstring-plus-int] 문자열에 추가되지 않습니다.

return "" + c; // Here
       ~~~^~~

참고 :이 경고를 끄려면 배열 인덱싱을 사용하십시오.


컴파일러가이 코드를 해석하는 방법에 대한 많은 설명이 있지만, 당신이 알고 싶었던 것은 당신이 잘못한 일입니다.

You appear to be expecting the + behavior from std::string. The problem is that neither of the operands actually is a std::string. C++ looks at the types of the operands, not the final type of the expression (here the return type, std::string) to resolve overloading. It won't pick std::string's version of + if it doesn't see a std::string.

If you have special behavior for an operator (either you wrote it, or got a library that provides it), that behavior only applies when at least one of the operands has class type (or reference to class type, and user-defined enumerations count too).

If you wrote

std::string("") + c

or

std::string() + c

or

""s + c // requires C++14

then you would get the std::string behavior of operator +.

(Note that none of these are actually good solutions, because they all make short-lived std::string instances that can be avoided with std::string(1, c))

The same thing goes for functions. Here's an example:

std::complex<double> ipi = std::log(-1.0);

You'll get a runtime error, instead of the expected imaginary number. That's because the compiler has no clue that it should be using the complex logarithm here. Overloading looks only at the arguments, and the argument is a real number (type double, actually).

Operator overloads ARE functions and obey the same rules.


This return statement

return "" + c;

is valid. There is used so called the pointer arithmetic. String literal "" is converted to pointer to its first character (in this case to its terminating zero) and integer value stored in c is added to the pointer. So the result of expression

"" + c

has type const char *

Class std::string has conversion constructor that accepts argument of type const char *. The problem is that this pointer can points to beyond the string literal. So the function has undefined behaviour.

I do not see any sense in using this expression. If you want to build a string based on one character you could write for example

return std::string( 1, c );

the difference between C++ and C# is that in C# string literals have type System.String that has overloaded operator + for strings and characters (that are unicode characters in C#). In C++ string literals are constant character arrays and the semantic of operator + for arrays and integers are different. Arrays are converted to pointers to their first elements and there are used the pointer arithmetic.

It is standard class std::string that has overloaded operator + for characters. String literals in C++ are not objects of this class that is of type std::string.

참고URL : https://stackoverflow.com/questions/25812411/something-in-c

반응형