2010-04-21 30 views
1

문자열 연산자 < <과 비트 시프 팅 연산자 < <을 한 행에 사용합니다. 약간 혼란 스럽습니다. 왜 코드 A)는 코드 B)와 동일한 출력을 생성하지 않습니까?연산자 << : std :: cout << i << (i << 1);

A)

int i = 4; 
std::cout << i << " " << (i << 1) << std::endl; //4 8 

B)

myint m = 4; 
std::cout << m << " " << (m << 1) << std::endl; //8 8 

클래스 민트 : 사전에

class myint { 
    int i; 
public: 
    myint(int ii) { 
     i = ii; 
    } 
    inline myint operator <<(int n){ 
     i = i << n; 
     return *this; 
    } 
    inline operator int(){ 
     return i; 
    } 
}; 

감사
아차

+0

거의 중복의 : http://stackoverflow.com/questions/2603312/the-result-of-int-c0-를 coutcc /. 대부분의 실제적인 목적을 위해 비록 수정을 한 연산자로 "<<"대신에 "++"를 사용 했음에도 불구하고 동일합니다 –

+2

@Jerry Coffin : 그들은 매우 유사하지만 전체 << << 대 < <혼돈과 <<가 통상적으로 인수를 변경하지 않는다는 사실 –

답변

8

두 번째 예는 정의되지 않은 동작입니다.

myint 클래스에서 <<= 인 것처럼 << 연산자를 정의했습니다. i << 1을 실행하면 i의 값은 수정되지 않지만 m << 1을 실행하면 m의 값은이 수정됩니다.

C++에서 중재 시퀀스 포인트없이 변수에 읽기 및 쓰기 (또는 두 번 이상 쓰는 것)가 모두 정의되지 않은 동작입니다. 함수 호출과 연산자는 인수와 관련이 없습니다. m << 1 업데이트되기 전에 또는 후에 m

std::cout << m << " " << (m << 1) << std::endl; 

가 출력 제 m 코드 여부 결정적이다. 실제로 코드가 완전히 이상하거나 크래시를 일으킬 수 있습니다. 정의되지 않은 동작은 문자 그대로 모든 것을 유도 할 수 있으므로 피해야합니다.myint<< 연산자를 정의하는 적절한 방법

하나는 :

myint operator<< (int n) const 
{ 
    return myint(this->i << n); 
} 

+1

과부하 연산자는 함수 호출입니다. –

+2

'std :: cout << m << ""<< (m << 1)'은'std :: cout.operator << (m) .operator << ("")와 동등합니다. 가장 바깥 쪽 연산자가 호출 될 때 사이의 순서 지점이 있지만 연산자 호출에 대한 내부 호출을 포함하여 연산자에 전달 된 인수의 평가 사이에 시퀀스 포인트가 없습니다. 다시 말하면,'f (a) .g (b())'에는'f' 호출과'g' 호출 사이에 시퀀스 포인트가있다. 그러나 'a'와 'b'에 대한 호출 순서는 정의되지 않습니다. –

+0

아마 당신은 당신의 코멘트에 설명이 없기 때문에, 많은 시퀀스 포인트 중 어느 것도 중요한 표현 사이에 하나도 없다는 것을 보장하지 않는다는 것이 명백하지 않기 때문에 아마도 당신은 당신의 대답을 업데이트해야합니다. –

2

귀하 < < 연산자는 실제로 < < = 연산자입니다. 당신이

std::cout << i << " " << (i <<= 1) << std::endl; //8 8 

으로 라인을 교체하는 경우는 m 전에 평가 (8) (8)

+6

문제를 강조했지만 "대답"에 정의되지 않은 동작이 있음 –

1

음 (< < 1 m)를 받아야하기 때문에 m은 < < 덮어 쓸 운영자와 같이 이미 8 보유하여 자신의 가치.

이것은 사용자측에서 잘못된 행동입니다. < <은 const이어야하며 개체가 변경되지 않아야합니다.

5

int < < X가 새로운 int를 반환합니다. myint < < X는 현재 myint를 수정합니다. 당신의 myint < < 통신 수는 이전을하기 위하여 고쳐 져야한다.

첫 번째로 8을 얻는 이유는 구현에서 m < < 1이 먼저 호출되기 때문입니다. 구현은 임의의 순서로 자유롭게 수행 할 수 있습니다.

0

때문에합니다 (this->가 아니라 내가 연산자를 오버로드 단지 내 스타일이 반드시 필요하다)의 << 운영자 myint는 lh를 수정합니다. 따라서 m << 1을 평가 한 후 m은 실제로 값 8을 갖지만 (i << 1은 8 만 반환하지만 i는 8과 같지 않음). m<<1cout << m 전에 실행되는지 여부는 지정되지 않으므로 (함수 또는 연산자의 인수가 평가되는 순서로 지정되지 않았으므로) 출력이 8 8 또는 4 8이 될지 여부는 지정되지 않습니다. m 이후

2

myInt 두 번째 예는 다시 작성할 수 있습니다와 같은 :

std::cout << m << " " << (m.operator<<(1)) << std::endl; 

"m"당신이 얻을 것이다 아무 말이 없다 그래서 표현식에 대한 평가의 순서는 m(m.operator<<(1))가 지정되지 m이 사용 된 1 번째 표현식 (이는 간단한 m 표현식입니다). 그래서 "4 8"의 결과를 얻거나 "8 8"을 얻을 수 있습니다.

설명 은 이 수정 될 때와 읽히는 시점 사이에 시퀀스 포인트 (적어도 하나의 함수 호출)가 있기 때문에 정의되지 않은 동작 인이 발생하지 않습니다. 그러나 하위 표현식의 평가 순서는 지정되지 않았으므로 컴파일러가 결과를 산출해야하지만 (적어도 합법적으로는 충돌 할 수는 없음) 결과가 생성되어야한다는 결과는 없습니다.

그래서이 문은 정의되지 않은 동작이있는 것처럼 유용합니다. 즉 매우 유용하지는 않습니다.

0

C++ 언어는 연산자 평가 순서를 정의하지 않습니다. 그것은 단지 그들의 연관성을 정의합니다.

결과가 표현식 내에서 operator<< 함수가 평가되는 시점에 따라 달라 지므로 결과는 정의되지 않습니다.

대수 operator $ 기능은 항상 const을하고 새로운 개체를 반환해야합니다 :

inline myint operator <<(int n) const { // ensure that "this" doesn't change 
    return i << n; // implicit conversion: call myint::myint(int) 
}