Programing

멤버 데이터에서 포인터 나 참조를 선호해야합니까?

lottogame 2020. 7. 6. 07:48
반응형

멤버 데이터에서 포인터 나 참조를 선호해야합니까?


다음은 질문을 설명하기위한 간단한 예입니다.

class A {};

class B
{
    B(A& a) : a(a) {}
    A& a;
};

class C
{
    C() : b(a) {} 
    A a;
    B b; 
};

그래서 B는 C의 일부를 업데이트 할 책임이 있습니다. lint를 통해 코드를 실행했으며 참조 멤버 lint # 1725에 대해 엉망이었습니다 . 여기에서는 기본 복사 및 할당을 충분히 돌보는 것에 대해 이야기하지만 기본 복사 및 할당도 포인터로 나쁘므로 이점이 거의 없습니다.

나체 포인터는 그 포인터를 삭제할 책임이있는 사람을 불확실하게 소개하기 때문에 항상 참조를 사용하려고합니다. 값으로 객체를 포함하는 것을 선호하지만 포인터가 필요한 경우 포인터를 소유하는 클래스의 멤버 데이터에 auto_ptr을 사용하고 객체를 참조로 전달합니다.

포인터가 null이거나 변경 될 수있는 경우 일반적으로 멤버 데이터에 포인터 만 사용합니다. 데이터 멤버에 대한 참조보다 포인터를 선호해야하는 다른 이유가 있습니까?

참조가 초기화 된 후에는 참조를 변경할 수 없으므로 참조를 포함하는 객체를 할당 할 수 없어야한다고 말하는 것이 사실입니까?


참조 멤버는 클래스 구현이 수행 할 수있는 작업 (제한 연산자 할당 방지 등)을 제한하고 클래스가 제공 할 수있는 이점을 제공하지 않기 때문에 피하십시오.

문제 예 :

  • 각 생성자의 이니셜 라이저 목록에서 참조를 초기화해야합니다.이 초기화를 다른 함수로 인수 분해 할 수있는 방법이 없습니다 ( C ++ 0x까지 편집 : C ++에는 위임 생성자가 있습니다 )
  • 참조는 리 바인드되거나 널이 될 수 없습니다. 이것은 이점이 될 수 있지만 리 바인딩을 허용하거나 멤버가 널이되도록 코드를 변경해야하는 경우 멤버의 모든 사용을 변경해야합니다.
  • 포인터 멤버와 달리 리팩토링에 필요할 수 있으므로 참조를 스마트 포인터 또는 반복자로 쉽게 바꿀 수 없습니다.
  • 참조가 사용될 때마다 값 유형 ( .연산자 등)처럼 보이지만 포인터처럼 작동합니다 (매끄럽게 할 수 있음). 예를 들어 Google 스타일 가이드

내 자신의 경험 법칙 :

  • 객체의 수명이 다른 객체의 수명에 의존하기를 원할 때 참조 멤버를 사용하십시오 . 다른 클래스의 유효한 인스턴스가 없으면 객체가 살아남을 수 없다는 명시적인 방법입니다. 할당과 생성자를 통해 참조 초기화를 가져야 할 의무. 인스턴스가 다른 클래스의 멤버인지 아닌지에 대해 가정하지 않고 클래스를 디자인하는 좋은 방법입니다. 당신은 그들의 삶이 다른 사례들과 직접 연결되어 있다고 가정합니다. 나중에 클래스 인스턴스 사용 방법을 변경할 수 있습니다 (새 인스턴스, 로컬 인스턴스, 클래스 멤버, 관리자의 메모리 풀에 의해 생성됨 등).
  • 다른 경우에 포인터 사용 : 나중에 멤버를 변경하려면 포인터 또는 const 포인터를 사용하여 지정된 인스턴스 만 읽도록하십시오. 해당 유형이 복사 가능해야한다면 어쨌든 참조를 사용할 수 없습니다. 때로는 특별한 함수 호출 (예 : init ()) 후에 멤버를 초기화해야하며 포인터를 사용하는 것 외에는 선택의 여지가 없습니다. 그러나 : 모든 멤버 함수에 assert를 사용하여 잘못된 포인터 상태를 신속하게 감지하십시오!
  • 객체 수명이 외부 객체의 수명에 의존하고 해당 유형도 복사 가능 해야하는 경우 포인터 멤버를 사용하지만 생성자에서 참조 인수를 사용 하면 생성 에이 객체의 수명이 의존한다는 것을 나타내는 방식으로 표시합니다 인수의 수명 동안 구현은 포인터를 사용하여 여전히 복사 가능합니다. 이러한 멤버가 사본으로 만 변경되고 유형에 기본 생성자가 없으면 유형이 두 목표를 모두 충족해야합니다.

객체는 할당 및 비교와 같은 다른 것들을 허용하지 않아야합니다. '부서', '직원', '감독'과 같은 개체가 포함 된 일부 비즈니스 모델을 고려하면 한 직원이 다른 직원에게 할당 될 경우를 상상하기 어렵습니다.

따라서 비즈니스 오브젝트의 경우 일대일 관계와 일대 다 관계를 포인터가 아닌 참조로 설명하는 것이 좋습니다.

그리고 아마도 1 또는 0의 관계를 포인터로 설명하는 것이 좋습니다.

따라서 '할당 할 수 없습니다'는 없습니다.
많은 프로그래머가 포인터와 함께 사용하기 때문에 참조 사용을 피하기 위해 인수를 찾을 수 있습니다.

회원으로서 포인터를 가지고 있으면 "만약의 경우"설명과 함께 사용하기 전에 사용자 또는 팀 구성원이 포인터를 계속해서 다시 확인해야합니다. 포인터가 0 일 수 있다면 포인터는 아마도 일종의 플래그로 사용되는데, 이는 모든 객체가 고유 한 역할을 수행해야하기 때문에 나쁘다.


가능하면 참조를 사용하고 필요할 때는 포인터를 사용하십시오.


In a few important cases, assignability is simply not needed. These are often lightweight algorithm wrappers that facilitate calculation without leaving the scope. Such objects are prime candidates for reference members since you can be sure that they always hold a valid reference and never need to be copied.

In such cases, make sure to make the assignment operator (and often also the copy constructor) non-usable (by inheriting from boost::noncopyable or declaring them private).

However, as user pts already commented, the same is not true for most other objects. Here, using reference members can be a huge problem and should generally be avoided.


As everyone seems to be handing out general rules, I'll offer two:

  • Never, ever use use references as class members. I have never done so in my own code (except to prove to myself that I was right in this rule) and cannot imagine a case where I would do so. The semantics are too confusing, and it's really not what references were designed for.

  • Always, always, use references when passing parameters to functions, except for the basic types, or when the algorithm requires a copy.

These rules are simple, and have stood me in good stead. I leave making rules on using smart pointers (but please, not auto_ptr) as class members to others.


Yes to: Is it true to say that an object containing a reference should not be assignable, since a reference should not be changed once initialised?

My rules of thumb for data members:

  • never use a reference, because it prevents assignment
  • if your class is responsible for deleting, use boost's scoped_ptr (which is safer than an auto_ptr)
  • otherwise, use a pointer or const pointer

I would generally only use a pointer in member data when the pointer could be null or could change. Are there any other reasons to prefer pointers over references for data members?

Yes. Readability of your code. A pointer makes it more obvious that the member is a reference (ironically :)), and not a contained object, because when you use it you have to de-reference it. I know some people think that is old fashioned, but I still think that it simply prevent confusion and mistakes.


I advise against reference data members becasue you never know who is going to derive from your class and what they might want to do. They might not want to make use of the referenced object, but being a reference you have forced them to provide a valid object. I've done this to myself enough to stop using reference data members.


If I understand the question correctly...

Reference as function parameter instead of pointer: As you pointed out, a pointer doesn't make it clear who owns the cleanup/initialization of the pointer. Prefer a shared point when you want a pointer, it's a part of C++ 11, and a weak_ptr when the validity of the data is not guaranteed through the lifetime of the class accepting the pointed to data.; also a part of C++ 11. Using a reference as a function parameter guarantees that the reference is not null. You have to subvert the language features to get around this, and we don't care about loose cannon coders.

Reference a a member variable: As as above in regards to data validity. This guaranties the pointed to data, then referenced, is valid.

Moving responsibility of variable validity to an earlier point in the code not only cleans up the later code (the the class A in your example), but also makes it clear to the person using.

In your example, which is a bit confusing (I'd really try to find a more clearer implementation), the A used by B is guaranteed for the lifetime of the B, since B is a member of A, so a reference reinforces this and is (perhaps) more clear.

And just in case (which is a low likely hood as it wouldn't make any sense in your codes context), another alternative, to use a non referenced, non pointer A parameter, would copy A, and make the paradigm useless - I really don't think you mean this as an alternative.

Also, this also guarantees you aren't able to change the data referenced, where a pointer can be modified. A const pointer would work, only if the referenced/pointer to data was not mutable.

Pointers are useful if the A parameter for B was not guaranteed to be set, or could be reassigned. And sometimes a weak-pointer is just too verbose for the implementation, and a good number of people either don't know what a weak_ptr is, or just dislike them.

Tear apart this answer, please :)

참고URL : https://stackoverflow.com/questions/892133/should-i-prefer-pointers-or-references-in-member-data

반응형