有人可以解释为什么指针没有初始化为NULL
吗?
例:
void test(){
char *buf;
if (!buf)
// whatever
}
该程序不会进入if的内部,因为buf
它不为null。
我想知道为什么在什么情况下我们需要一个带有垃圾桶的变量,特别是指向内存中垃圾桶的指针?
有人可以解释为什么指针没有初始化为NULL
吗?
例:
void test(){
char *buf;
if (!buf)
// whatever
}
该程序不会进入if的内部,因为buf
它不为null。
我想知道为什么在什么情况下我们需要一个带有垃圾桶的变量,特别是指向内存中垃圾桶的指针?
Answers:
我们都意识到应该初始化指针(和其他POD类型)。
然后问题变成“谁应该初始化它们”。
好吧,基本上有两种方法:
让我们假设编译器初始化了开发人员未显式初始化的任何变量。然后,我们遇到了这样的情况:初始化变量不是一件容易的事,而开发人员未在声明点执行此操作的原因是,他/她需要执行一些操作然后进行赋值。
因此,现在的情况是,编译器已向代码中添加了一条额外的指令,以将变量初始化为NULL,然后再添加开发人员代码以进行正确的初始化。或者在其他条件下,该变量可能永远不会使用。在这两种情况下,很多C ++开发人员都会以额外的指令为代价大喊大叫。
这不只是时间。而且还有空间。在很多环境中,两种资源都很宝贵,开发人员也不愿放弃任何一种资源。
但是:您可以模拟强制初始化的效果。大多数编译器会警告您未初始化的变量。因此,我总是将警告级别尽可能地提高。然后告诉编译器将所有警告视为错误。在这种情况下,大多数编译器将为未初始化但已使用的变量生成错误,从而阻止生成代码。
在TC ++ PL(特别版p.22)中引用Bjarne Stroustrup:
功能的实现不应在不需要该功能的程序上增加大量开销。
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中完成的方式。为什么要像在C中那样完成,这是另一个问题,但是我认为零开销原则在某种程度上涉及了此设计决策。
指针只是另一种类型。如果你创建一个int
,char
或任何其他类型的POD它不初始化为零,所以为什么要一个指针?对于这样编写程序的人来说,这可能被认为是不必要的开销。
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
是一种学术练习,因为打字少。但是,从教育的角度来看,上面的代码非常有用。稍加修改(对“占位” ctor / dtor和赋值操作),就可以轻松地将其扩展到各种类型的智能指针,包括作用域指针(在析构函数上免费)和引用计数指针,方法是添加inc /设置或清除m_pPointer时的dec操作。
请注意,静态数据被初始化为0(除非您另有说明)。
是的,您应该始终尽可能晚地使用初始值声明变量。像这样的代码
int j;
char *foo;
阅读时应响起警钟。我不知道是否可以说服任何棉绒,因为它是100%合法的。
C ++来自C的背景-并且有一些原因会导致这种情况:
C,甚至比C ++更是汇编语言的替代品。它不会做任何您不要求做的事情。因此:如果您想将其为NULL,请执行此操作!
此外,如果您使用C之类的裸机语言为空,则会自动出现一致性问题:如果您分配了某些内容-应该自动将其清零吗?那么在堆栈上创建的结构呢?是否所有字节都应清零?全局变量呢?像“(** 0x18);”这样的语句呢?那不是意味着存储器位置0x18应该清零吗?
calloc()
。
您所说的这些指针是什么?
对于异常安全,始终使用auto_ptr
,shared_ptr
,weak_ptr
和他们的其他变体。
好的代码的标志是不包含对的单个调用delete
。
auto_ptr
和替代unique_ptr
。
好家伙。真正的答案是很容易将内存清零,这是指针的基本初始化。这也与初始化对象本身无关。
考虑到大多数编译器在最高级别给出的警告,我无法想象在最高级别进行编程并将其视为错误。由于将它们调高甚至从来没有为我节省过大量代码生成中的一个错误,因此我不推荐这样做。
NULL
,它初始化到是一样多的错误。