누군가 포인터가 초기화되지 않은 이유를 설명해 주 NULL
시겠습니까?
예:
void test(){
char *buf;
if (!buf)
// whatever
}
프로그램은 buf
null이 아니기 때문에 if 내부로 들어 가지 않습니다.
나는 왜 어떤 경우에 쓰레기가있는 변수, 특히 메모리의 쓰레기를 다루는 포인터가 필요한지 알고 싶습니다.
누군가 포인터가 초기화되지 않은 이유를 설명해 주 NULL
시겠습니까?
예:
void test(){
char *buf;
if (!buf)
// whatever
}
프로그램은 buf
null이 아니기 때문에 if 내부로 들어 가지 않습니다.
나는 왜 어떤 경우에 쓰레기가있는 변수, 특히 메모리의 쓰레기를 다루는 포인터가 필요한지 알고 싶습니다.
답변:
우리 모두는 포인터 (및 기타 POD 유형)가 초기화되어야한다는 것을 알고 있습니다.
그러면 질문은 '누가 초기화해야 하는가'가됩니다.
기본적으로 두 가지 방법이 있습니다.
컴파일러가 개발자가 명시 적으로 초기화하지 않은 변수를 초기화했다고 가정 해 보겠습니다. 그런 다음 변수 초기화가 사소한 일이 아니고 개발자가 선언 지점에서이를 수행하지 않은 이유는 몇 가지 작업을 수행 한 다음 할당해야하기 때문입니다.
이제 컴파일러가 변수를 NULL로 초기화하는 코드에 추가 명령을 추가 한 다음 나중에 올바른 초기화를 수행하기 위해 개발자 코드가 추가되는 상황이 발생했습니다. 또는 다른 조건에서는 변수가 잠재적으로 사용되지 않습니다. 많은 C ++ 개발자는 추가 명령을 지불하고 두 가지 조건 모두에서 비명을 질렀습니다.
시간 문제가 아닙니다. 그러나 또한 공간. 두 리소스 모두 프리미엄이 있고 개발자도 포기하고 싶지 않은 많은 환경이 있습니다.
그러나 : 강제 초기화의 효과를 시뮬레이션 할 수 있습니다. 대부분의 컴파일러는 초기화되지 않은 변수에 대해 경고합니다. 그래서 저는 항상 경고 수준을 가능한 최고 수준으로 설정합니다. 그런 다음 컴파일러에게 모든 경고를 오류로 처리하도록 지시하십시오. 이러한 조건에서 대부분의 컴파일러는 초기화되지 않았지만 사용 된 변수에 대해 오류를 생성하여 코드 생성을 방지합니다.
TC ++ PL에서 Bjarne Stroustrup 인용 (Special Edition p.22) :
기능의 구현은이를 필요로하지 않는 프로그램에 상당한 오버 헤드를 부과해서는 안됩니다.
D
. 초기화를 원하지 않는 경우이 구문 float f = void;
또는 int* ptr = void;
. 이제 기본적으로 초기화되지만 정말로 필요한 경우 컴파일러가 수행하는 것을 중지 할 수 있습니다.
초기화에는 시간이 걸리기 때문입니다. 그리고 C ++에서 변수로 가장 먼저해야 할 일은 명시 적으로 초기화하는 것입니다.
int * p = & some_int;
또는:
int * p = 0;
또는:
class A {
public:
A() : p( 0 ) {} // initialise via constructor
private:
int * p;
};
C ++의 모토 중 하나는 다음과 같습니다.
당신은 당신이 사용하지 않는 것에 대해 지불하지 않습니다
바로 이러한 이유로, operator[]
의 vector
인덱스가 예를 들어, 범위 외에있는 경우 클래스는 확인하지 않습니다.
역사적 이유로, 주로 이것이 C에서 수행되는 방식이기 때문입니다. C에서 그렇게 수행되는 이유는 또 다른 질문입니다. 그러나 제로 오버 헤드 원칙 이이 설계 결정에 어떻게 든 관련 되었다고 생각합니다 .
게다가, 우리는 당신이 그것을 날려 버릴 때에 대한 경고를 가지고 있습니다 : 당신의 컴파일러에 따라 "값이 할당되기 전에 사용될 수 있습니다"또는 유사한 동사.
경고와 함께 컴파일하는 거 맞죠?
변수가 초기화되지 않는 것이 합리적 일 수있는 상황이 거의없고 기본 초기화의 비용이 적습니다. 왜 그렇게합니까?
C ++는 C89가 아닙니다. C조차도 C89가 아닙니다. 선언과 코드를 혼합 할 수 있으므로 초기화 할 적절한 값이있을 때까지 선언을 연기해야합니다.
포인터는 또 다른 유형입니다. int
, char
또는 다른 POD 유형 을 생성하면 0으로 초기화되지 않는데 왜 포인터가 필요합니까? 이것은 이와 같은 프로그램을 작성하는 사람에게 불필요한 오버 헤드로 간주 될 수 있습니다.
char* pBuf;
if (condition)
{
pBuf = new char[50];
}
else
{
pBuf = m_myMember->buf();
}
초기화 할 것이라는 것을 알고 있다면 pBuf
, 메서드의 맨 위에서 처음 만들 때 프로그램에 비용이 발생하는 이유는 무엇입니까? 이것이 제로 오버 헤드 원칙입니다.
항상 NULL로 초기화되는 포인터를 원하는 경우 C ++ 템플릿을 사용하여 해당 기능을 에뮬레이트 할 수 있습니다.
template<typename T> class InitializedPointer
{
public:
typedef T TObj;
typedef TObj *PObj;
protected:
PObj m_pPointer;
public:
// Constructors / Destructor
inline InitializedPointer() { m_pPointer=0; }
inline InitializedPointer(PObj InPointer) { m_pPointer = InPointer; }
inline InitializedPointer(const InitializedPointer& oCopy)
{ m_pPointer = oCopy.m_pPointer; }
inline ~InitializedPointer() { m_pPointer=0; }
inline PObj GetPointer() const { return (m_pPointer); }
inline void SetPointer(PObj InPtr) { m_pPointer = InPtr; }
// Operator Overloads
inline InitializedPointer& operator = (PObj InPtr)
{ SetPointer(InPtr); return(*this); }
inline InitializedPointer& operator = (const InitializedPointer& InPtr)
{ SetPointer(InPtr.m_pPointer); return(*this); }
inline PObj operator ->() const { return (m_pPointer); }
inline TObj &operator *() const { return (*m_pPointer); }
inline bool operator!=(PObj pOther) const
{ return(m_pPointer!=pOther); }
inline bool operator==(PObj pOther) const
{ return(m_pPointer==pOther); }
inline bool operator!=(const InitializedPointer& InPtr) const
{ return(m_pPointer!=InPtr.m_pPointer); }
inline bool operator==(const InitializedPointer& InPtr) const
{ return(m_pPointer==InPtr.m_pPointer); }
inline bool operator<=(PObj pOther) const
{ return(m_pPointer<=pOther); }
inline bool operator>=(PObj pOther) const
{ return(m_pPointer>=pOther); }
inline bool operator<=(const InitializedPointer& InPtr) const
{ return(m_pPointer<=InPtr.m_pPointer); }
inline bool operator>=(const InitializedPointer& InPtr) const
{ return(m_pPointer>=InPtr.m_pPointer); }
inline bool operator<(PObj pOther) const
{ return(m_pPointer<pOther); }
inline bool operator>(PObj pOther) const
{ return(m_pPointer>pOther); }
inline bool operator<(const InitializedPointer& InPtr) const
{ return(m_pPointer<InPtr.m_pPointer); }
inline bool operator>(const InitializedPointer& InPtr) const
{ return(m_pPointer>InPtr.m_pPointer); }
};
Foo *a
를 사용합니다 InitializedPointer<Foo> a
.- Foo *a=0
타이핑이 적기 때문에 순수하게 학문적 인 연습을 합니다. 그러나 위의 코드는 교육적인 관점에서 매우 유용합니다. 약간의 수정 ( "placeholding"ctor / dtor 및 할당 작업에 대한)으로 inc /를 추가하여 범위 포인터 (소멸자에서 해제 됨) 및 참조 계수 포인터를 포함한 다양한 유형의 스마트 포인터로 쉽게 확장 할 수 있습니다. m_pPointer가 설정되거나 지워질 때 dec 작업.
정적 데이터는 0으로 초기화됩니다 (달리 언급하지 않는 한).
그리고 예, 항상 가능한 한 늦게 초기 값으로 변수를 선언해야합니다. 같은 코드
int j;
char *foo;
읽을 때 알람 벨을 울려 야합니다. 100 % 합법적이기 때문에 어떤 보푸라기 라도 잉어에 대해 설득 할 수 있는지 모르겠습니다 .
또 다른 가능한 이유는 링크 타임에 포인터에 주소가 주어 지지만 포인터의 간접 주소 지정 / 역 참조는 프로그래머의 책임이기 때문입니다. 일반적으로 컴파일러는 그다지 신경 쓰지 않지만 포인터를 관리하고 메모리 누수가 발생하지 않는지 확인하는 부담은 프로그래머에게 전달됩니다.
간단히 말해서 링크 타임에 포인터 변수에 주소가 주어진다는 의미에서 초기화됩니다. 위의 예제 코드에서 이는 충돌하거나 SIGSEGV를 생성하도록 보장됩니다.
어떤 시도가없이 역 참조 할 경우 정신을 위해, 항상 그런 식으로, NULL 포인터를 초기화 malloc
하거나 new
프로그램의 잘못이 동작하는 이유에 프로그래머 의지 단서.
이것이 도움이되고 이해되기를 바랍니다.
글쎄, 만약 C ++가 포인터를 초기화했다면, "C ++는 C보다 느리다"라고 불평하는 C 사람들은 진짜로 매달릴 것이다;)
C ++는 C 배경에서 비롯되었으며 여기에서 돌아 오는 몇 가지 이유가 있습니다.
C는 C ++보다 훨씬 더 어셈블리 언어 대체입니다. 당신이 지시하지 않은 것은 아무것도하지 않습니다. 따라서 : NULL을 원할 경우 수행하십시오!
또한 C와 같은 베어 메탈 언어에서 null을 사용하면 자동으로 일관성 질문이 나타납니다. malloc을 사용하면 자동으로 0으로 설정해야합니까? 스택에 생성 된 구조체는 어떻습니까? 모든 바이트를 0으로해야합니까? 전역 변수는 어떻습니까? "(* 0x18);"과 같은 문장은 어떻습니까? 그렇다면 메모리 위치 0x18이 제로화되어야 함을 의미하지 않습니까?
calloc()
.
당신이 말하는이 포인터는 무엇입니까?
예외 안전을 위해, 항상 사용 auto_ptr
, shared_ptr
, weak_ptr
과 다른 변종.
좋은 코드의 특징은 단일 호출을 포함하지 않는 것 delete
입니다.
auto_ptr
및 대체 unique_ptr
.
오 소년. 진짜 대답은 포인터의 기본 초기화 인 메모리를 제로화하기 쉽다는 것입니다. 객체 자체를 초기화하는 것과도 관련이 없습니다.
대부분의 컴파일러가 가장 높은 수준에서 제공하는 경고를 고려하면 가장 높은 수준에서 프로그래밍하고 오류로 처리하는 것을 상상할 수 없습니다. 생성 된 엄청난 양의 코드에서 버그를 하나도 저장하지 않았기 때문에 이것을 권장 할 수 없습니다.
NULL
그에게 초기화하는 것은 단지 많은 오류가 발생합니다.