本文将分享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)
- 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)
-
类型差异
-
NULL
和0
#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]
-
这里
NULL
是long long int
类型. -
不同编译器实现不同.
-
-
问题
-
NULL
和0
都是内置类型,当出现同时重载指针和内置类型时. 会出现错误匹配或者二义性.
-
-
错误匹配
#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
新特性.
-
-
-
好处
-
可读性
#include <iostream> void* show() { return nullptr; } int main () { auto s = show(); if (0 != s) { } if (NULL != s) { } if (nullptr != s) { } }
-
nullptr
是后面的主流. -
NULL
和nullptr
一起有点混. -
0
都不知道返回的是什么类型.
-
-
-
模板
-
分析
-
前面介绍了
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); }
-
直接报错.
-
-
-
总结
-
内置类型方便,安全.
-
兼容性强.不推荐使用
NULL,0
;
-
ALTER TABLE,在null null列中设置null,PostgreSQL 9.1
我的意思是,我想做这样的事情:
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?
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,"",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
我有以下方法:
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 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的相关信息,请在本站查询。
本文标签: