2016-10-23 1 views
-3

비 const 멤버 함수 (const를) 참조 멤버 변수를 전달할 때 : (경고없이, 그냥 질문 상승 오류로 실행

  • 내가 경고 컴파일러를 얻을 안을 MSVC2013을) 또는
  • 내가 따라야 할 새로운 가이드 라인을 알아야합니까, 아니면
  • 나는 완전히 바보 같은 짓을하고 있습니까?

저는 멤버 함수 내에 있고 다른 멤버 함수에 const& 매개 변수로 멤버 변수를 전달합니다. 호출 된 함수는 const이 아닙니다. 나는 그것에 대해 생각한다면, 나는 단지 그렇게해서는 안된다는 것을 확신합니다.

우연히 원래 전달 된 멤버 변수를 수정할 때 const& 매개 변수가 마술처럼 변경 될 수 있습니다. 에, 허용되지 않습니다, 선언되지 않고 const. 코드에서

예 :

struct S 
{ 
    void caller() 
    { 
     called_one(this->memvar); 
    } 

    void called_one(const int& x) 
    { 
     // ... 
     this->memvar = 2; // changes x! That's surprising... at least for this function 
     // ... 
    } 

private: 
    int memvar{}; 
} 

나는 실수로 다시 오류로 실행되지 좋을 것이다 생각합니다. 아마도 언어 나 컴파일러가이를 방지하는 것이 가장 쉬운 작업이 아닌가? 일부 인기있는 가이드 라인에서 아직 그 문제를 발견하지 못했습니다.

UPDATE :

은 아마도 내가 행동이 이상한 찾을 수없는 것을 명확히해야한다. 앨리어싱 된 변수가 왜 달라 지는지 궁금하지 않습니다. 뭔가 잘못하고,

... 그리고 caller 인 하나

UPDATE)에 대한 답변은 단지 called_one 자신, 이상한 발견 할 기능에 초점을 맞춘 경우 그것은 좋은 것입니다. 하지만 그는 (코드를 읽음으로써) 그 사실을 깨달을 수있는 공정한 기회가 있다고 생각합니다. 그는 호출 된 함수가 매개 변수를 통하지 않고 수정할 수도 있다는 것을 알기 위해 별칭을 전달합니다. 그러면 호출 된 함수 내에서 예기치 않은 동작이 발생할 수 있습니다.

그래서이 특별한 경우에도 컴파일러가 도움이되지 않거나 합리적이지 않은 경우 가이드 라인의 형태로 그 함정을 소개하는 것이 왜 가치가 없거나 유용하지 않은지 나는 알지 못합니다.

+1

당신은'수정할 수 없습니다 const_cast를 사용하여 int&로 다시 전송할 수 있습니다 x'이지만, 'this-> memvar'는'const'로 표시되지 않고 둘 다 함수 자체가 아닙니다. 그래서 마지막 대안, 바보 같은 일을하는 것은 일어나는 일입니다. :) –

+0

_ 나는 그것에 대해 생각할 때, 나는 그저 그렇게하지 말아야한다고 확신한다. 글쎄, 할 수있어. 당신의 추론이 잘못되었습니다. 그게 다야. – skypjack

+0

'memvar'는 const가 아니므로 모든 것이 excepted로 동작합니다. 'x'는'const int &'이므로'x'를 통해'memvar'를 수정할 수 없습니다. – Asu

답변

4

귀하의 질문은

f(int& x, const int& y) { x = 2; } 

을 정의하고 다음 경고없이 두 번째 인수 x을 수정

f(x, x); 

를 호출하는 것과 동일합니다. 방금 두 인수 사이에 별칭을 만들었습니다. 따라서 호출이 첫 번째 인수를 수정하면 두 번째 인수도 수정됩니다.

컴파일러는 변수 사이의 모든 별칭 정보를 알 수있는 방법이 없습니다. 그 일은 가능한 모든 별칭에 대해 올바른 코드를 제공하는 것입니다. 호출이 서명을 존중하므로 컴파일러는 경고를 제공해서는 안됩니다.

UPDATE :

는 같은 정의되지 않은 동작을 방지하기 위해 언어 수준에서 가이드 라인이 없습니다. 별칭은 많은 양식을 취할 가능성이 큽니다. 예를 들어, 함수는 (tree, list, vector) 데이터 구조를 해당 요소의 이니셔티브에서 루트에서 수정할 수 있습니다. 그런 다음 루트에서 요소에 도달하여 실수로 요소를 수정하거나 지원을 악화시킬 수 있습니다. 말씀 드렸듯이 이러한 점에주의를 기울이는 것은 프로그래머의 책임입니다 ( ).

컴파일러는 인수를보고 두 인수가 동일한 유형 및 다른 const 정보가있는 (사소한) 별칭에 있는지 감지 할 수 있습니다. 그러나 때때로 프로그래머들은 경고없이 그러한 행동을 원한다. 예 :

void mul_assign(double& x, const double& y) { x *= y; } 
void sqr_assign(double& x) { mul_assign(x, x); } 
+0

Mh, 죄송합니다. 왜 이런 일이 발생하는지 이상하지 않습니다. 그러나 컴파일러 작업이 아니며 프로그래머가 앨리어싱에 대한 전반적인 시각을 유지해야한다는 귀하의 말은 올바른 방향으로 향합니다. – yau

+0

당신이 옳았다는 것이 옳았습니다. – Franck

+0

자, 나를위한 본질은 : 프로그래머가 실제로 그렇게하려고하는 상황이 있습니다. 그래서 '절대하지 마라.'라는 지침이 있어서는 안된다. – yau

0

코드는 완벽하게 합법적 그냥 간단한

int x = 0; 
const int &x_r = x; // x_r can't be changed directly 
x = 42; // also changes (the value referenced by) x_r 

내가 일반적으로 코드 나쁜 디자인을 고려할 것 (하지만 그건 왜 이러는거야, 맥락없이 이야기하기 어렵다). 당신이 int을 수정하고 있기 때문에,

void called_one(const int x) // x is guaranteed not to change 
{ ... } 
0

이 코드는 법적 : 당신이 귀하의 경우 별칭을 피하려면

, 단지 값을 기준으로 x을 통과 (적어도 더 큰 구조체없는 가정) , 아니 const int&. 참조는 const 포인터에 대한 향상된 구문 설탕으로 간주 될 수 있습니다. (. : - 다음은 오른쪽의 요소에 적용이 시작되는 시점 아니라면 const이, 왼쪽에있는 요소에 적용 NB)

void called_one(const int *const x) // const pointer to const int 
{ 
    memvar = 2; 
} 

:이 코드는 다음과 같이 동작 의미 xmemvar을 가리 킵니다. 따라서 memvar을 수정하면 x 포인트가 수정됩니다. x 그 자체는 이 아니며이 수정되고 이 수정 될 수 없습니다. 은 const이기 때문에 수정할 수 없습니다. 참고 문헌과 동일합니다.

그러나 const은 그 자체로 원래 값을 수정할 수 없습니다. 여기서는 x 만 사용하여 x을 수정할 수 없음을 나타냅니다.

또한 int&const int&으로 줄일 수 있습니다. 괜찮습니다. (당신은! 다른 초기 유형에 있던 const의 삭제되지 않는 경우, 즉 UB입니다)하지만 당신은 또한

void called_one(const int& x) 
{ 
    const_cast<int&>(x) = 2; // Legal (and illegal if the `x` passed is actually `const`) 
} 
관련 문제