🚙

💨 💨 💨

×

  • Categories

  • Archives

  • Tags

  • About

智能指针笔记

Posted on 04-11-2015 | In Misc

有些错误是编译器查不到的, 这种错误是最可怕的, 当项目大了之后,
即使用 Valgrind 也很难定位,
因为裸指针在团队合作中使用很容易导致其他成员忘记释放或多次释放, 所以在团队合作中一般使用智能指针.

而智能指针用的不好, 结果可能适得其反.

所以我们聊一下智能指针的几点注意事项.

总结自 C++ Primer.

一个简单的包含删除器的例子演示

#include<iostream>
#include<functional>
#include<memory>

using std::cout;
using std::endl;
using std::bind;
using namespace std::placeholders;

int testBind( int* a, int b, int c )
{
cout << *a + b + c << endl;
return *a;
}

struct Foo
{
Foo() = default;
Foo( const Foo & a )
{
data = a.data;
std::cout << "复制构造" << std::endl;
}
void print_sum( int n1, int n2 )
{
std::cout << n1 + n2 << '\n';
}
int data = 10;
};

int main()
{
//绑定类成员函数用对象的指针
Foo foo;
auto f3 = std::bind( &Foo::print_sum, &foo, 95, _1 );
f3( 5 );

auto check_testBind = std::bind( testBind, std::placeholders::_1, 3, 9 );
int * p = new int( 7 );
cout << check_testBind( p ) << endl;

shared_ptr<int> pi( new int(),
check_testBind );
*pi = 88;

shared_ptr<int> pii( new int( 12 ),
std::bind( testBind, std::placeholders::_1, 32, 19 ) );

std::function< int( int* ) > test_function_bind =
std::bind( testBind, std::placeholders::_1, 331, 9 );

cout << "test_function_bind( p, 331, 9 ) = " << test_function_bind( p ) << endl;;

shared_ptr<int> piii( new int( 112 ),
test_function_bind );

return 0;
}

打印结果 :

100
119
7
347
test_function_bind( p, 331, 9 ) = 7
452
63
100
请按任意键继续. . .

智能指针陷阱

智能指针可以提供对动态分配的内存安全而又方便的管理,但这建立在正确使用的
前提下 。 为了正确使用智能指针,我们必须坚持一些基本规范 :

  • 不使用相同的内置指针值初始化(或 reset) 多个智能指针 。
  • 不 delete get ( ) 返 回的指针 。
  • 不使用 get () 初始化或 reset 另 一 个智能指针 。
  • 如果你使用 get () 返 回的指针,记住当最后一个对应的智能指针销 毁 后, 你 的
    指 针就 变为无 效 了 。
  • 如果你使用智能指针管理的资源不是 new 分配的内存 , 记住传递给它一个删除
    器( 参见 12. 1.4 节 , 第 415 页和 12. 1.5 节 , 第 419 页)。

尽量用make_shared而非new

shared_ptr 可以协调对象的析构 , 但这仅限于其自身的拷贝 ( 也 是 shared_ptr)
之间。

这也是为什么我们推荐使用 make_shared 而不是 new 的原因 。

这样 , 我们就能在分配对象的同时就将 shared_ptr 与之绑定,
从而避免了无意中将同一块内存绑定到多个独立创建的 shared_ptr 上 。(这是最容易犯的错)

总结 : 所以我们要尽量一开始就用make_shared来分配动态内存, 而不是先new一个出来, 再找机会将它转为智能指针.

考虑下面对 shared_ptr 进行操作的函数 :

// 在函数被调用时 ptr 被创建并初始化
void process(shared_ptr<int> ptr)
{
// 使用 ptr
} // ptr 离 开作用域,被销毁

process 的参数是传值方式传递的,因此实参会被拷贝到 ptr 巾 。 拷贝 一 个 shared_ptr
会递增其引用讨数,因此, 在 process 运行过程中,引用七| 数值至少为 2 。 当 process
结束时, ptr 的引用计数会边喊,但不会变为 0 。 因此,当用音11变 11 ptr 被销毁时, ptr
指向的内存不会被释放 。

使用此函数的正确方法是传递给它一个 shared_ptr :

shared_ptr<int> p(new int(42)) ; // 引用计数为 1
process(p); // 拷贝 p 会递增它的引用计数 ;在 process 中引用计数位为 2
int i = *p; // 正确:引用计数位为 1

虽然不能传递给 process 一 个内置指针,但可以传递 给它 一 个(临时的)
shared_ptr , 这个 shared_ptr 是用 一个内 置指针显式构造的 。 但是,这样做很可能
会导致错误 :

int *x(new int(1024)); // 危险 x 是一个普通指针,不是一个智能指针
process(x) ; // 错误 : 不能将 int* 转换为 一个 shared_ptr<int>
process(shared_ptr<int>(x)); // 合法的,但内存会被释放!
int j = *x ; //未定义的 x 是一个空悬指针!

在上面的调用中 , 我们将一个临时 shared_ptr 传递给 process 。 当这个调用所在的表
达式结束时,这个临时对象就被销毁了 。 销毁这个临时变量会递减引用计数,此时引用计
数就变为 0 了 。 因此,当临时对象被销毁时 , 它所指向的内存会被释放 。
但 x 继续指 向 (已经释放的)内存,从而变成一个空悬指针。如果试图使用 x 的值,
其行为是未定义的 。

当将一个 shared_ptr 绑定到一个普通指针时 , 我们就将内存的管理责任交给了这
个 shared_ptr 一旦这样做 了 , 我们就不应该再使用内置指针来访问 shared_ptr 所
指向的内存了

不要使用 get 初始化另一个智能指针或为智能指针赋值

智能指针类型定义了 一个名为 get 的函数(参见表 1 2. J ),它返回一个内置指针,
指向智能指针管理的对象 。 此函数是为了这样一种情况而设计的 : 我们需要向不能使用智
能指针的代码传递一个内置指针。使用 get 返回的指告| 的代码不能 delete 此指针 。
虽然编译器不会给出错误信息 , 但将另一个智能指针也绑定到 get 返回的指针上是
错误的 :

shared_ptr<int> p(new int(42)) ; // 引 用计数为 1
int *q = p . get() ; // 正确 · 但使用 q 时妥注意,不要让它管理的指针被释放
{ // 新程序块
// 未定义:两个独立的 shared_ptr 指 向 相同的内存
shared ptr<int> (q) ;
} // 程序块结束, q 被销毁 , 它指向的内存被待放
int foo = *p ; // 未定义 p 指向的内存 已 经被释放了

在本例中, p 和 q 指 向相同的内存。由于它们是相互独立创建的,因此各自的引用计数都
是 1。 当 q 所在的程序块结束时 , q 被销毁 , 这会导致 q 指向的内存被释放 。 从而 p 变成
一个空悬指针,意味着当我们试图使用 p 时,将发生未定义的行为 。 而且 , 当 p 被销毁时 ,
这块内存会被第二次 delete 。

get 用来将指针的访问权限传递给代码,你只有在确定代码不会 get.
特别是,永远不要用 get 初始化另一个智能指针 del ete 指针或者为另一个智能指针赋值.

linux一些不要想当然的事(一)之目录权限

Posted on 03-18-2015 | In Linux

目录的可读/可写/可执行权限

不要把目录的这几个权限和档案的这几个权限混淆了, 不要想当然的以为是差不多的, 差很多!
记忆技巧 : 档案的rwx是针对于档案的内容来设计的, 而目录的rwx是针对于目录的文件名列表来设计的

. . .

Linux常用运维命令(df和free和top)笔记整理(三)

Posted on 03-11-2015 | In Linux

df

df命令用于显示磁盘分区上的可使用的磁盘空间。默认显示单位为KB。可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息。

  • -a或–all:包含全部的文件系统;
  • –block-size=<区块大小>:以指定的区块大小来显示区块数目;
  • -h或–human-readable:以可读性较高的方式来显示信息;
  • -H或–si:与-h参数相同,但在计算时是以1000 Bytes为换算单位而非1024 Bytes;
  • -i或–inodes:显示inode的信息;
  • -k或–kilobytes:指定区块大小为1024字节;
  • -l或–local:仅显示本地端的文件系统;
  • -m或–megabytes:指定区块大小为1048576字节;
  • –no-sync:在取得磁盘使用信息前,不要执行sync指令,此为预设值;
  • -P或–portability:使用POSIX的输出格式;
  • –sync:在取得磁盘使用信息前,先执行sync指令;
  • -t<文件系统类型>或–type=<文件系统类型>:仅显示指定文件系统类型的磁盘信息;
  • -T或–print-type:显示文件系统的类型;
  • -x<文件系统类型>或–exclude-type=<文件系统类型>:不要显示指定文件系统类型的磁盘信息;
  • –help:显示帮助;
  • –version:显示版本信息

. . .

Linux常用运维命令(netstat和lsof)笔记整理(二)

Posted on 03-09-2015 | In Linux

netstat

netstat命令用来打印Linux中网络系统的状态信息,可让你得知整个Linux系统的网络情况。

  • -a或–all:显示所有连线中的Socket;
  • -A<网络类型>或–<网络类型>:列出该网络类型连线中的相关地址;
  • -c或–continuous:持续列出网络状态;
  • -C或–cache:显示路由器配置的快取信息;
  • -e或–extend:显示网络其他相关信息;
  • -F或–fib:显示FIB;
  • -g或–groups:显示多重广播功能群组组员名单;
  • -h或–help:在线帮助;
  • -i或–interfaces:显示网络界面信息表单;
  • -l或–listening:显示监控中的服务器的Socket;
  • -M或–masquerade:显示伪装的网络连线;
  • -n或–numeric:直接使用ip地址,而不通过域名服务器;
  • -N或–netlink或–symbolic:显示网络硬件外围设备的符号连接名称;
  • -o或–timers:显示计时器;
  • -p或–programs:显示正在使用Socket的程序识别码和程序名称;
  • -r或–route:显示Routing Table;
  • -s或–statistice:显示网络工作信息统计表;
  • -t或–tcp:显示TCP传输协议的连线状况;
  • -u或–udp:显示UDP传输协议的连线状况;
  • -v或–verbose:显示指令执行过程;
  • -V或–version:显示版本信息;
  • -w或–raw:显示RAW传输协议的连线状况;
  • -x或–unix:此参数的效果和指定”-A unix”参数相同;
  • –ip或–inet:此参数的效果和指定”-A inet”参数相同。

. . .

Linux常用运维命令(iostat)笔记整理(一)

Posted on 03-07-2015 | In Linux

在linux服务器开发过程中, 经常需要各种命令配合来查看各种状态,所以整理了一些老的笔记来备忘。

iostat

iostat主要用于监控系统设备的IO负载情况,iostat首次运行时显示自系统启动开始的各项统计信息,之后运行iostat将显示自上次运行该命令以后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息

  • -c 仅显示CPU统计信息.与-d选项互斥.
  • -d 仅显示磁盘统计信息.与-c选项互斥.
  • -k 以K为单位显示每秒的磁盘请求数,默认单位块.
  • -t 在输出数据时,打印搜集数据的时间.
  • -V 打印版本号和帮助信息.
  • -x 输出扩展信息.

. . .

python的struct模块

Posted on 03-02-2015 | In Misc

struct, 这玩意c/c++也有, 顾名思义, 能联想到这玩意是啥了

模块的主要作用就是对python基本类型值与

用python字符串格式表示的C struct类型间

的转化(This module performs conversions between Python values and C structs represented as Python strings.)

基本用法

import struct
import binascii
values = (1, 'abc', 2.7)
s = struct.Struct('I3sf')
packed_data = s.pack(*values)
unpacked_data = s.unpack(packed_data)

print 'Original values:', values
print 'Format string :', s.format
print 'Uses :', s.size, 'bytes'
print 'Packed Value :', binascii.hexlify(packed_data)
print 'Unpacked Type :', type(unpacked_data), ' Value:', unpacked_data

输出为:

Original values: (1, 'abc', 2.7) 
Format string : I3sf
Uses : 12 bytes
Packed Value : 0100000061626300cdcc2c40
Unpacked Type : <type 'tuple'> Value: (1, 'abc', 2.700000047683716)

代码中,

首先定义了一个元组数据,

包含int、string、float三种数据类型,

然后定义了struct对象,并制定了format‘I3sf’,

  • I 表示int,

  • 3s表示三个字符长度的字符串,

  • f 表示 float。最后通过struct的pack和unpack进行打包和解包。通过输出结果可以发现,

value被pack之后,

转化为了一段二进制字节串,

而unpack可以把该字节串再转换回一个元组,

但是值得注意的是对于float的精度发生了改变,

这是由一些比如操作系统等客观因素所决定的。打包之后的数据所占用的字节数与C语言中的struct十分相似。定义format可以参照官方api提供的对照表:

字节序设置

另一方面,打包的后的字节顺序默认上是由操作系统的决定的,

当然struct模块也提供了自定义字节顺序的功能,

可以指定大端存储、小端存储等特定的字节顺序,

对于底层通信的字节顺序是十分重要的,

不同的字节顺序和存储方式也会导致字节大小的不同。在format字符串前面加上特定的符号即可以表示不同的字节顺序存储方式,

例如采用小端存储 s = struct.Struct(‘<I3sf’)就可以了。官方api library 也提供了相应的对照列表:

MySQL入门二之一些小注意点

Posted on 03-02-2015 | In DB

distinct关键字

distinct是应用于所有列的, 而不是某一个列

mysql> select * from test_table;
+------+------+
| one | two |
+------+------+
| 56 | 12 |
| 52 | 10 |
| 56 | 12 |
| 56 | 13 |
+------+------+
4 rows in set (0.00 sec)

mysql> select distinct one, two from test_table;
+------+------+
| one | two |
+------+------+
| 56 | 12 |
| 52 | 10 |
| 56 | 13 |
+------+------+
3 rows in set (0.00 sec)

mysql> select distinct one from test_table;
+------+
| one |
+------+
| 56 |
| 52 |
+------+
2 rows in set (0.00 sec)

. . .

MySQL入门一之增删查改与关联

Posted on 02-27-2015 | In DB

增删改查

  • INSERT INTO table_name (列1, 列2,…) VALUES (值1, 值2,….)

  • DELETE FROM 表名称 WHERE 列名称 = 值

  • UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值

  • SELECT 列名称 FROM 表名称

关联

SQL join 用于根据两个或多个表中的列之间的关系,从这些表中查询数据。

Join和Key概绍

有时为了得到完整的结果,我们需要从两个或更多的表中获取结果。我们就需要执行 join。
数据库中的表可通过键将彼此联系起来。主键(Primary Key)是一个列,在这个列中的每一行的值都是唯一的。在表中,每个主键的值都是唯一的。这样做的目的是在不重复每个表中的所有数据的情况下,把表间的数据交叉捆绑在一起。
请看 “Persons” 表:

Id_P LastName FirstName Address City
1 Adams John Oxford Street London
2 Bush George Fifth Avenue New York
3 Carter Thomas Changan Street Beijing

请注意,”Id_P” 列是 Persons 表中的的主键。这意味着没有两行能够拥有相同的 Id_P。即使两个人的姓名完全相同,Id_P 也可以区分他们。
接下来请看 “Orders” 表:

Id_O OrderNo Id_P
1 77895 3
2 44678 3
3 22456 1
4 24562 1
5 34764 65

请注意,”Id_O” 列是 Orders 表中的的主键,同时,”Orders” 表中的 “Id_P” 列用于引用 “Persons” 表中的人,而无需使用他们的确切姓名。
请留意,”Id_P” 列把上面的两个表联系了起来。

下面列出了您可以使用的 JOIN 类型,以及它们之间的差异。

  • JOIN(INNER JOIN): 如果左右表中都有至少一个匹配,则返回行
  • LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
  • RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
  • FULL JOIN: 只要其中一个表中存在匹配,就返回行

注 : JOIN使用on的, 而不是where.

使用Join(INNER JOIN)

除了上面的方法,我们也可以使用关键词 JOIN 来从两个表中获取数据。
如果我们希望列出所有人的定购,可以使用下面的 SELECT 语句:

SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
INNER JOIN Orders
ON Persons.Id_P = Orders.Id_P
ORDER BY Persons.LastName

结果集:

LastName FirstName OrderNo
Adams John 22456
Adams John 24562
Carter Thomas 77895
Carter Thomas 44678

使用Left Join

现在,我们希望列出所有的人,以及他们的定购 - 如果有的话。
您可以使用下面的 SELECT 语句:

SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
LEFT JOIN Orders
ON Persons.Id_P=Orders.Id_P
ORDER BY Persons.LastName

结果集:

LastName FirstName OrderNo
Adams John 22456
Adams John 24562
Carter Thomas 77895
Carter Thomas 44678
Bush George - - - -

LEFT JOIN 关键字会从左表 (Persons) 那里返回所有的行,即使在右表 (Orders) 中没有匹配的行。

使用Right Join

现在,我们希望列出所有的定单,以及定购它们的人 - 如果有的话。
您可以使用下面的 SELECT 语句:

SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
RIGHT JOIN Orders
ON Persons.Id_P=Orders.Id_P
ORDER BY Persons.LastName

结果集:

LastName FirstName OrderNo
Adams John 22456
Adams John 24562
Carter Thomas 77895
Carter Thomas 44678
34764

RIGHT JOIN 关键字会从右表 (Orders) 那里返回所有的行,即使在左表 (Persons) 中没有匹配的行。

使用Full Join

现在,我们希望列出所有的人,以及他们的定单,以及所有的定单,以及定购它们的人。
您可以使用下面的 SELECT 语句:

SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
FULL JOIN Orders
ON Persons.Id_P=Orders.Id_P
ORDER BY Persons.LastName

结果集:

LastName FirstName OrderNo
Adams John 22456
Adams John 24562
Carter Thomas 77895
Carter Thomas 44678
Bush George
34764

FULL JOIN 关键字会从左表 (Persons) 和右表 (Orders) 那里返回所有的行。如果 “Persons” 中的行在表 “Orders” 中没有匹配,或者如果 “Orders” 中的行在表 “Persons” 中没有匹配,这些行同样会列出。

1…22232425262728293031323334353637
Mike

Mike

🚙 🚗 💨 💨 If you want to create a blog like this, just follow my open-source project, "hexo-theme-neo", click the GitHub button below and check it out ^_^ . It is recommended to use Chrome, Safari, or Edge to read this blog since this blog was developed on Edge (Chromium kernel version) and tested on Safari.

11 categories
289 posts
111 tags
about
GitHub Spotify
© 2013 - 2025 Mike