GVKun编程网logo

nullptr 还是 NULL 0(nullptr和0)

9

本文将分享nullptr还是NULL0的详细内容,并且还将对nullptr和0进行详尽解释,此外,我们还将为大家带来关于ALTERTABLE,在nullnull列中设置null,PostgreSQL9

本文将分享nullptr 还是 NULL 0的详细内容,并且还将对nullptr和0进行详尽解释,此外,我们还将为大家带来关于ALTER TABLE,在null null列中设置null,PostgreSQL 9.1、c – 为什么函数模板不理解NULL但是使用nullptr?、C# null,string.Empty,"",DBNull 的区别、c# – 对于expr == null和expr!= null,与null的比较计算结果为true的相关知识,希望对你有所帮助。

本文目录一览:

nullptr 还是 NULL 0(nullptr和0)

nullptr 还是 NULL 0(nullptr和0)

  1. 类型差异

    • NULL0

      #include <iostream>
      template <typename T>
      void show( T&& a) {
         a.error();
      }
      
      int main () {
         show(NULL);
      }
      
      • 输出

      D:\codes\cfile\Test\test.cpp: In instantiation of ''void show(T&&) [with T = long long int]'':
      D:\codes\cfile\Test\test.cpp:8:14:   required from here
      D:\codes\cfile\Test\test.cpp:4:7: error: request for member ''error'' in ''a'', which is of non-class type ''long long int''
          a.error();
          ~~^~~~~
      [Finished in 328ms]
      
      • 这里NULLlong long int类型.

      • 不同编译器实现不同.

    • 问题

      • NULL0都是内置类型,当出现同时重载指针和内置类型时. 会出现错误匹配或者二义性.

    • 错误匹配

      #include <iostream>
      
      void show(long long int) {
         std::cout << __LINE__ << std::endl;
      }
      
      void show(void *) {
         std::cout << __LINE__ << std::endl;
      }
      
      
      int main () {
         show(NULL);
      }
      
    • 二义性

      #include <iostream>
      
      void show(bool) {
         std::cout << __LINE__ << std::endl;
      }
      
      void show(void *) {
         std::cout << __LINE__ << std::endl;
      }
      
      
      int main () {
         show(NULL);
      }
      
    • 小结

      • nullptr是关键字.不需要include

      • nullptr有自己的类型,不会和普通类型出现二义性.

      • nullptr可以转化为任意类型的指针.

      • nullptr有编译器支持,C++11新特性.

  2. 好处

    • 可读性

      #include <iostream>
      
      void* show() {
         return nullptr;
      }
      
      int main () {
         auto s = show();
         if (0 != s) {
         }
         if (NULL != s) {
         }
         if (nullptr != s) {
         }
      }
      
      • nullptr是后面的主流.

      • NULLnullptr一起有点混.

      • 0都不知道返回的是什么类型.

  3. 模板

    • 分析

      • 前面介绍了NULL,0当作空指针,间接隐式转换还可以,但是通过模板就会变回原形.

      • 变回原型就不匹配,会出现警告之类的.

    • 隐式匹配

      #include <iostream>
      
      void show(void*) {
      
      }
      
      int main () {
         show(0);
         show(NULL);
      }
      
      • 关键是还不能出现自身类型的重载,出现了就可能出错.

    • 模板现原形

      #include <iostream>
      void cool(void*) {
      
      }
      template <typename T>
      void show(T&&a) {
         cool(a);
      }
      
      int main () {
         show(nullptr);
         // show(0);
         // show(NULL);
      }
      
      • 直接报错.

  4. 总结

    • 内置类型方便,安全.

    • 兼容性强.不推荐使用NULL,0;

ALTER TABLE,在null null列中设置null,PostgreSQL 9.1

ALTER TABLE,在null null列中设置null,PostgreSQL 9.1

我有一个表与非空列,如何设置一个null值在这一列作为默认值?

我的意思是,我想做这样的事情:

postgres=# ALTER TABLE person ALTER COLUMN phone SET NULL;

但它显示:

postgres=# ALTER TABLE person ALTER COLUMN phone SET NULL;
ERROR:  Syntax error at or near "NULL"
LINE 1: ALTER TABLE person ALTER COLUMN phone SET NULL;
ALTER TABLE person ALTER COLUMN phone DROP NOT NULL;

更多细节在手册:http://www.postgresql.org/docs/9.1/static/sql-altertable.html

c – 为什么函数模板不理解NULL但是使用nullptr?

c – 为什么函数模板不理解NULL但是使用nullptr?

我有一个功能
int f(std::shared_ptr<MyClass> sptr);

之后我编写以下模板以便能够调用它(和其他一些)函数:

template <typename Func,typename ArgType>
auto call(Func func,ArgType arg) -> decltype(func(arg))
{
    return func(arg);
}

当我尝试将此模板与NULL一起使用时,为什么在第三行中出现错误?

auto r0 = f(0); // OK
auto r1 = call(f,nullptr); // OK
auto r2 = call(f,NULL); // ERROR! WHY??

1>------ Build started: Project: ConsoleApplication1,Configuration: Debug x64 ------
1>  main.cpp
1>main.cpp(245): error C2893: Failed to specialize function template 'unkNown-type call(Func,Arg)'
1>          With the following template arguments:
1>          'Func=int (__cdecl *)(std::shared_ptr<MyClass>)'
1>          'Arg=int'
========== Build: 0 succeeded,1 Failed,0 up-to-date,0 skipped ==========

解决方法

线索在这里:
Arg=int

NULL必须是空指针常量,在C 11之前,它必须是一个值为零的整数常量.在您的实现中,它具有int类型,可能是文字0.

因此模板参数推导为int,不能转换为shared_ptr,因此错误.

至于其他人:

auto r0 = f(0); // OK

如果直接传递给函数,则可以将文字0视为空指针常量,并将其转换为shared_ptr.在调用中,参数不是文字,而是int类型的变量,无法转换.

auto r1 = call(f,nullptr); // OK

nullptr有自己的类型,可以转换为shared_ptr.

C# null,string.Empty,

C# null,string.Empty,"",DBNull 的区别

【null】

null 在C# 中是一个关键字,表示不引用任何对象的空引用的文字值。 null 是引用类型变量的默认值。 普通值类型不能为 null。

null 在 VS 中定位不出来具体是怎么定义的。一般通过类名映射过来的关键字,都可以定位到声明位置。所以null是比较特殊的。

这个东西要跟踪源头还比较麻烦,感觉找不到具体定义。

MSDN上说明很简单:null 关键字是表示不引用任何对象的空引用的文字值。 null 是引用类型变量的默认值。 普通值类型不能为 null。

stock overflow 上有一段回答:

There are three things in C# that "null" can be. A reference, a pointer, and a nullable type.

The implementation of C# on the CLR represents a null reference by zero bits. (Where the number of bits is the appropriate size to be a managed pointer on the particular version of the CLR that you''re running.)

Unsurprisingly, a null pointer is represented the same way. You can demonstrate this in C# by making an unsafe block, making a null pointer to void, and then converting that to IntPtr, and then converting the IntPtr to int (or long, on 64 bit systems). Sure enough, you''ll get zero.

以下翻译(来自Google在线翻译):

C#中有三个“null”可以。 引用,指针和可空类型。

CLR上的C#实现表示零位的空引用。 (其中位数是适合您正在运行的CLR的特定版本上的托管指针的大小。)

不出所料,空指针以相同的方式表示。 您可以在C#中通过创建一个不安全的块,将空指针转换为void,然后将其转换为IntPtr,然后将IntPtr转换为int(或64位系统上的long)来证明这一点。 果然,你会得到零。

Stack Overflow 上的这个回答是基本从比较底层说明的。

那么咱们也从相对比较底层看下c/c++中null的定义。

来自 https://zh.cppreference.com/w/c/types/NULL 

C:

 

C++ 

 

【string.Empty】

这个是 string 类中的一个制度静态变量。也就肯定的说明了 string.Empty 是一个存在静态对象。这个就跟 null 区别开了。那到底具体是个什么呢?

string.Empty 其实就是 “”。

MSDN解释:

https://docs.microsoft.com/zh-cn/dotnet/api/system.string.empty?view=netframework-4.7.2

 

string.Empty 虽然跟 “” 是相等的,但是一般在给 string 初始化为空字符串的时候,一般建议用string.Empty,因为“”在赋值给string对象的时候,是你新创建了一个空字符串,而用Empty是将你的字符串对象指向了全局的只读的空字符串,这样相对来说性能能优化一些。

 

【“”】

 “” 代表一个空字符串。什么意思,首先是一个字符串对象,但是特殊的是,这个字符串没有内容,这可绝非 null。

 

个人经验简单形容下 null 和 “”。引用类型好比书目录,类对象好比书中内容。如果引用类型不为null,那么目录后面就有页码,如果为null,那么目录后面的页码就为0或者没有页码。那么没有页码,你说这个目录怎么找页数,也就是空引用了。 

 

【DBNull】

 咱先看MSDN注解:

DBNull类表示不存在的值。 例如,在数据库中,表的行中的列不可能包含任何数据。 也就是说,列被视为根本不存在,而不是只是不具有值。 一个DBNull对象都表示不存在的列。 此外,COM 互操作使用DBNull类,以区分 VT_NULL 变体,用于指示不存在的值和 VT_EMPTY 变体,用于指示未指定的值。

DBNull类型是一个单一实例类,这意味着只有一个DBNull对象存在。 DBNull.Value成员表示单独DBNull对象。 DBNull.Value 可用于显式将不存在的值分配到数据库字段中,尽管大多数的 ADO.NET 数据提供程序自动分配的值DBNull字段没有有效的值。 您可以确定从数据库字段中检索某个值是否DBNull通过将为该字段的值传递值DBNull.Value.Equals方法。 但是,某些语言和数据库对象提供一些方法,使其更轻松地确定数据库字段的值是否为DBNull.Value。 其中包括 Visual BasicIsDBNull函数,Convert.IsDBNull方法,DataTableReader.IsDBNull方法,和IDataRecord.IsDBNull方法。

不要混淆这一概念null在面向对象的编程语言与DBNull对象。 在面向对象的编程语言中,null表示不存在的对象的引用。 DBNull 表示一个未初始化的变量或不存在的数据库列。

 

从上面注解可以看出,DBNull只要用在数据库和COM互操作中。而DBNull中有个Value字段,这个字段是一个静态只读字段,也就是全局唯一静态DBNull对象,不是null。

当我们在用ADO.NET操作数据库时,遇到数据库返回字段值为NULL时,就需要用DBNull来判断,而不能用null来判断。

看看MSDN对DBNull.Value的注解:

DBNull 是一个单一实例类,这意味着可以存在此类的此实例。

如果数据库字段有缺失数据,则可以使用DBNull.Value属性来显式分配DBNull对象的字段的值。 但是,大多数数据访问接口自动执行此操作。

若要评估的数据库字段,以确定它们的值是否DBNull,可以将传递到的字段值DBNull.Value.Equals方法。 但是,很少使用此方法,因为有多种其他方法来评估缺少数据的数据库字段。 其中包括 Visual BasicIsDBNull函数,Convert.IsDBNull方法,DataTableReader.IsDBNull方法,IDataRecord.IsDBNull方法和其他几种方法。

所以这下就明白了吧,这就是为什么我们用IDataReader读取数据库字段信息时,要用DBNull.Value来判断是否为空,然后在转换或者其他操作。

https://docs.microsoft.com/zh-cn/dotnet/api/system.dbnull.value?view=netframework-4.7.2

 

c# – 对于expr == null和expr!= null,与null的比较计算结果为true

c# – 对于expr == null和expr!= null,与null的比较计算结果为true

我看到一些非常奇怪的东西,我无法解释.我猜测我不熟悉的C#的一些边缘情况,还是运行时/发射器的错误?

我有以下方法:

public static bool HistoryMessageExists(DBContext context,string id)
{
    return null != context.Getobject<HistoryMessage>(id);
}

在测试我的应用程序时,我看到它是不正常的 – 它为我知道的不存在于我的数据库的对象返回true.所以我停止了在方法和立即,我跑了以下:

context.Getobject<HistoryMessage>(id)
null
null == context.Getobject<HistoryMessage>(id)
true
null != context.Getobject<HistoryMessage>(id)
true

Getobject的定义如下:

public T Getobject<T>(object pk) where T : DBObject,new()
{
    T rv = Connection.Get<T>(pk);

    if (rv != null)
    {
        rv.AttachToContext(this);
        rv.IsInserted = true;
    }

    return rv;
}

有趣的是,当将表达式转换为对象时,正确评估比较:

null == (object)context.Getobject<HistoryMessage>(id)
true
null != (object)context.Getobject<HistoryMessage>(id)
false

没有平等的运算符覆盖.

编辑:事实证明有一个操作符超载,这是不正确的.但是,为什么在内部方法通用Getobject中正确评估这个方法,在这种情况下,rv的类型为HistoryMessage.

public class HistoryMessage : EquatableIdentifiableObject
{
    public static bool HistoryMessageExists(DBContext context,string id)
    {
        var rv = context.Getobject<HistoryMessage>(id);
        bool b = rv != null;
        return b;
    }

    public static void AddHistoryMessage(DBContext context,string id)
    {
        context.InsertObject(new HistoryMessage { Id = id });
    }
}

public abstract partial class EquatableIdentifiableObject : DBObject,IObservableObject
{
    public event PropertyChangedEventHandler PropertyChanged;

    [PrimaryKey]
    public string Id { get; set; }

    //...
}

public abstract partial class EquatableIdentifiableObject
{
    //...

    public static bool operator ==(EquatableIdentifiableObject self,EquatableIdentifiableObject other)
    {
        if (ReferenceEquals(self,null))
        {
            return ReferenceEquals(other,null);
        }

        return self.Equals(other);
    }

    public static bool operator !=(EquatableIdentifiableObject self,null))
        {
            return !ReferenceEquals(other,null);
        }

        return !self.Equals(other);
    }
}

public abstract class DBObject
{
    [Ignore]
    protected DBContext Context { get; set; }

    [Ignore]
    internal bool IsInserted { get; set; }

    //...
}

这里发生了什么?

解决方法

>如你已经澄清的那样,==操作符失败,因为您的重载不正确.
>当转换为对象时,==操作符正常工作,因为它是被使用的对象的==的实现,而不是EquatableIdentifiableObject.
>在方法Getobject中,操作符正确地求值,因为它不是EquatableIdentifiableObject的正在使用的==的实现.在C#泛型中,运行时解析(至少在这里是相关的),而不是在编译时解决.注意==是静态而不是虚拟的.所以类型T在运行时被解析,但是调用==必须在编译时解决.在编译时,当编译器解析==它不会知道使用EquatableIdentifiableObject的==的实现.因为类型T有这个约束:其中T:DBObject,new(),DBObject的实现(如果有的话)将被使用.如果DBObject没有定义==,那么将使用第一个基类的实现(直到对象).

有关EquatableIdentifiableObject的实现的更多评论==:

>您可以替换此部分:

if (ReferenceEquals(self,null))
{
     return ReferenceEquals(other,null);
}

有:

// If both are null,or both are the same instance,return true.
if (object.ReferenceEquals(h1,h2))
{
    return true;
}

>更换更有力

public static bool operator !=(EquatableIdentifiableObject self,EquatableIdentifiableObject other)
{
    ...
}

有:

public static bool operator !=(EquatableIdentifiableObject self,EquatableIdentifiableObject other)
{
    return !(self == other);
}

>为==定义签名的方法略有误导.第一个参数命名为self,第二个命名为other.如果==是一个实例方法就可以了.由于它是一种静态方法,所以名字自身有点误导.更好的名称将是o1和o2或沿着这条线的东西,以便两个操作数在更平等的基础上对待.

我们今天的关于nullptr 还是 NULL 0nullptr和0的分享已经告一段落,感谢您的关注,如果您想了解更多关于ALTER TABLE,在null null列中设置null,PostgreSQL 9.1、c – 为什么函数模板不理解NULL但是使用nullptr?、C# null,string.Empty,"",DBNull 的区别、c# – 对于expr == null和expr!= null,与null的比较计算结果为true的相关信息,请在本站查询。

本文标签: