2012年8月24日

   如果数据库会话创建了本地临时表 #temtable,则仅会话可以使用该表,会话断开连接后就将该表删除。如果创建了 ##temtable全局临时表,则数据库中的任何用户均可使用该表。如果该表在您创建后没有其他用户使用,则当您断开连接时该表删除。如果您创建该表后另一个用户在使用该 表,则SQL Server 将在您断开连接并且所有其他会话不再使用该表时将其删除。

   如果本地临时表由存储过程创建或由多个用户同时执行的应用程序创建,则 SQL Server 必须能够区分由不同用户创建的表。为此,SQL Server 在内部为每个本地临时表的表名追加一个数字后缀。存储在 tempdb 数据库的 sysobjects 表中的临时表,其全名由 CREATE TABLE 语句中指定的表名和系统生成的数字后缀组成。为了允许追加后缀,为本地临时表指定的表名 table_name 不能超过 116 个字符。

   当存储过程完成时,将自动除去在存储过程中创建的本地临时表。由创建表的存储过程执行的所有嵌套存储过程都可以引用此表。但调用创建此表的存储过程的进程无法引用此表。

临时表位于tempdb系统数据库。

SQL SERVER临时表: 临时表与永久表相似,但临时表存储在 tempdb 中,当不再使用时会自动删除。有本地和全局两种类型的临时表,二者在名称、可见性和可用性上均不相同。本地临时表的名称以单个数字符号 (#) 打头;它们仅对当前的用户连接是可见的;当用户从 Microsoft® SQL Server™ 2000 实例断开连接时被删除。全局临时表的名称以数学符号 (##) 打头,创建后对任何用户都是可见的,当所有引用该表的用户从 SQL Server 断开连接时被删除。 例如,如果创建名为 employees 的表,则任何人只要在数据库中有使用该表的安全权限就可以使用该表,除非它已删除。如果创建名为 #employees 的本地临时表,只有您能对该表执行操作且在断开连接时该表删除。如果创建名为 ##employees 的全局临时表,数据表中的任何用户均可对该表执行操作。如果该表在您创建后没有其他用户使用,则当您断开连接时该表删除。如果该表在您创建后有其他用户使用,则 SQL Server在所有用户断开连接后删除该表

posted @ 2012-08-24 12:47 mildcat| 编辑 收藏

2010年7月14日

  1、在dev c++ IDE下,输入下面代码,检测string的实现机制。

 1#include <string>
 2using namespace std;
 3
 4int main()
 5{
 6    string str1 = "hello";
 7    string str2(str1);
 8    
 9    printf( "str1 address:%p\n", str1.c_str());
10    printf( "str2 address:%p\n", str2.c_str());
11    printf( "\n" );
12        
13    str1[0];
14    printf( "str1 address:%p\n", str1.c_str());
15    printf( "str2 address:%p\n", str2.c_str());
16    printf( "\n" );
17    
18    string str3(str1);
19    printf( "str1 address:%p\n", str1.c_str());
20    printf( "str3 address:%p\n", str3.c_str());
21    printf( "\n" );
22    
23    string str4(str2);
24    printf( "str2 address:%p\n", str2.c_str());
25    printf( "str4 address:%p\n", str4.c_str());
26    printf( "\n" );
27    
28    system("PAUSE");
29    return EXIT_SUCCESS;
30}

2、输出结果为:
 1/* output:
 2    str1 address:0036101C
 3    str2 address:0036101C
 4    
 5    str1 address:0036103C
 6    str2 address:0036101C
 7    
 8    str1 address:0036103C
 9    str3 address:0036105C
10    
11    str2 address:0036101C
12    str4 address:0036101C    
13*/


3、结果解析

     3.1   见代码第9行和第10行,为什么str1和str2的地址一致?
            
            因为string内部的实现机制为引用计数,string的拷贝构造函数并非真正的去进行字符串拷贝,只是将字符串的引用数加1。

           str1.c_str()和str2.c_str()实际上指的还是同一个字符串,同一块内存。

     3.2   见代码第14行和第15行,为什么经过str1[0]这个看似无关痛痒的一行代码后,str1和str2的地址不再一致了?
            
            具体而言,是str1的地址变化了,str2的地址保持不变。str1[0]到底做了什么?

            string重载了[],一个是non-const版本,一个是const版本

           char& operator[](size_t idx);

           const char& operator[](size_t idx)const;
      
            在上面的代码中,调用的是non-const版本,由于这个函数版本身是无法得知代码上下文中调用自己是为了读还是为了写,也就是无法区分以下两种情况:

            cout  << str[0];//读

            str[0] = 'w';   // 写

            理论上而言,在读时不需要在string内部对原字符串拷贝一份,只有在写时才需要对原字符串拷贝,由于无法区分读和写,或者说区分读和写比较困难,

            所以我想DEV C++在string的实现上,应该是不区分读和写上下文,统一认为是写操作。
            
            这样就造成一旦调用operator[],肯定在该函数内部进行了字符串拷贝操作。

            从这个角度理解,str1的地址发生了变化,也是在情理之中的事情啦。

   3.3、见代码第19行和第20行,为什么str1拷贝给str3后,两者的地址不一致?
              
            是的,这个比较令人费解,尤其是考虑到str1刚拷贝给str2后,str1与str2的地址却是一致?貌似这是相悖的。

            其实不然,仔细看一下,不难发现,str1是在调用完operator[]后才变成这个样子的。

           看来operator[]不仅是进行了字符串拷贝,还对str1对象做了其他手脚。究竟是什么呢?

            让我们先暂时撇开这个问题,看一下以下代码:
1     string s1("test");
2     char* p = &s1[0];
3     string s2(s1);
4     *= 'T';      
上述代码中,第2行取了s1[0]的地址,然后在未来的某一刻再通过指针更改s1[0]的取值,见第4行代码。

在未来的某一刻到来之前,所有对于是s1的拷贝,都不能进行引用计数,只能老老实实的进行字符串赋值,

否则一旦通过指针更改s1[0]的取值,那么所有s1的拷贝对象的值将都被修改。

假如operator[]的实现中只是进行了字符串拷贝,那么在上述第4行代码执行后,s1与s2的值将都被改变,即s1 = s2 = 'Test';

这显然是与事实不符的,正确的结果应该是s1 = 'Test',s2 = 'test';所以这就需要operator[]的实现中增加一个共享标志位,

用来表示该字符串是否可还可以被共享,每当调用operator[],operator[]都会将这个标志位置成非共享状态

(默认值为共享状态),一旦置成了非共享状态,那么将永远不会再还原!

所以凡是调用了operator[]函数的string对象,都将从共享状态转变成非共享状态,对于这种对象的拷贝,都无法进行引用计数。

再回到原来的那个问题,就可以理解为什么str1拷贝给str3之后,str1和str3的地址不一致了。

 




         
      
posted @ 2010-07-14 22:19 mildcat 阅读(925) | 评论 (0)编辑 收藏
仅列出标题