KISS

尊重 谦虚 宽容


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

C++11之Move 构造函数和Move 赋值操作符

发表于 2014-04-13   |   分类于 C_Plus_Plus   |  

Move语义是C++11中为了提高性能,减少临时对象的构造和析构而引入的新的语义环境,和Move语义相关的还有右值引用(rvalue reference),这里我们总结一下,Move语义的引入带来了哪些好处,当我们定义一个类时需要注意什么。

####Move语义及移动构造函数####

我们通过代码来看一下Move语义出现的原因及必要性。

假设我们有如下的类定义,TestClass类中含有一个Char*类型的成员变量,为了实现内存的管理,按照The Big Three原则,我们需要为这个类定义拷贝构造函数,析构函数和赋值操作符。类的代码如下:

++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class TestClass
{
public:
TestClass(char* _array) : array_pointer(_array){
cout << "Constructor Invoked" << std::endl;
}
~TestClass(){
cout << "Destructor is InVoked" << std::endl;
delete array_pointer;
}
TestClass(const TestClass& rhs){
cout << "Copy Constructor is Invoked" << std::endl;
size_t len = strlen(rhs.array_pointer) + 1;
this->array_pointer = new char[len];
memcpy(this->array_pointer, rhs.array_pointer, len);
}

private:
char* array_pointer;
};

其中拷贝构造函数的语义为:当我们采用一个对象A去构造新的对象时,拷贝构造函数会被自动调用。拷贝构造函数的参数为const TestClass& rhs决定了我们无法改变rhs的值。在下列情况下会使用拷贝构造函数:
++
1
2
TestClass A(x);
TestClass B(x+y);

对于对象A的构造,拷贝构造函数完全符合我们的期望,因为我们使用了一个 lvalue来构造A,我们不希望改变x的内容,以便以后继续保持对x的引用。但是对于对象B的构造过程,拷贝构造函数明显做了多余的事情:

我们采用rvalue即一个临时变量来构造B,在B构造之后,临时变量会被销毁,我们不需要保持对这个临时变量的引用。因此,我们完全可以直接将构造函数中参数rhs的array_pointer指针直接给B,这样一来就可以省下B中array_pointer的初始化以及临时变量中array_pointer的释放过程。

阅读全文 »

深入ObjectiveC Runtime之(三)NSObject类与NSObject接口

发表于 2014-04-09   |   分类于 iOS   |  

在学习ObjectiveC Runtime代码是你会发现,在系统中除了一个名为NSObject的类之外,还存在一个同样名字为NSObject的接口(Protocol),这不禁让我们有疑问,NSObject接口存在的原因是什么,同样的名字难道不会有冲突吗?

我们先看一下接口 NSObject的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@protocol NSObject

- (BOOL)isEqual:(id)object;
- (NSUInteger)hash;

- (Class)superclass;
- (Class)class;
- (id)self;
- (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

- (BOOL)isProxy;

- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;

- (BOOL)respondsToSelector:(SEL)aSelector;

- (id)retain OBJC_ARC_UNAVAILABLE;
- (oneway void)release OBJC_ARC_UNAVAILABLE;
- (id)autorelease OBJC_ARC_UNAVAILABLE;
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;

- (NSString *)description;
@optional
- (NSString *)debugDescription;

@end

我们平时使用的runtime类型判断接口,以及performSelector等都定义在以NSObject为名的Protocol当中。这些方法在我们平时的编程过程中被大量使用,基本上所有的类都可以respond to这些方法,而我们的类都是继承自NSObject的,他们为什么会有NSObject Protocol当中声明的方法呢,唯一的解释就是Class NSObject 实现了 NSObject Protocol,在runtime的代码中我们也可以得到印证
1
2
3
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}

实际上在ObjectiveC中,interface和protocol的名字是可以相同的,因为在语言中不存在任何可以产生歧义的语法,也就是说interface和protocol使用于完全不同的语法环境,因此可以有相同的名字。

我们还可以进一步思考NSObject Protocol存在的必要性。在JAVA中,所有的类都是java.lang.Object的子类(Object是唯一的ROOT Class),而ObjectiveC中并不是所有的类都是NSObject的子类(有些类继承自NSProxy而不是NSObject)。因此在ObjectiveC中,为了给所有的类提供某些通用的接口,就必须保证所有的ROOT Class,都去实现某一个Protocol,NSObject Protocol就因此诞生,即所有的root class,包括NSObject和NSProxy都会实现NSObject Protocol, 我想这才是NSObject Protocol存在的根本原因。

深入ObjectiveC Runtime之(二)安装Clang

发表于 2014-04-03   |   分类于 iOS   |  

在上一篇中我们通过阅读代码,了解了ObjectiveC的内部对象模型的实现,接下来我们继续通过代码来了解ObjectiveC是如何加载一个类,以及ObjectiveC是如何实现对Category的支持的。

我们需要利用Clang来生成一部分中间代码,帮助我们了解runtime的运行机制,因此我们首先需要安装Clang。

Clang是LLVM的前端,可以用来编译C,C++,ObjectiveC等语言。传统的编译器通常分为三个部分,前端(frontEnd),优化器(Optimizer)和后端(backEnd)。在编译过程中,前端主要负责词法和语法分析,将源代码转化为抽象语法树;优化器则是在前端的基础上,对得到的中间代码进行优化,使代码更加高效;后端则是将已经优化的中间代码转化为针对各自平台的机器代码。Clang则是以LLVM为后端的一款高效易用,并且与IDE结合很好的编译前端。

我们需要自己下载LLVM与Clang源代码进行编译,步骤如下:

lang=shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm 

cd llvm/tools
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
cd ../..

cd llvm/projects
svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
cd ../..

mkdir build
cd build
../llvm/configure
make

至此,Clang 安装完毕,你可以使用clang --help来验证是否正确安装。

工欲善其事必先利其器,安装Clang主要是为我们今后的学习做准备,我本身对编译器没有特别深入的学习,如果你对Clang感兴趣可以参考这里。

Android通过代码设置控件点击时颜色变化

发表于 2014-03-30   |   分类于 Android   |  
android通过代码设置View 不同状态时背景颜色和字体颜色
阅读全文 »

深入ObjectiveC Runtime之对象模型

发表于 2014-03-26   |   分类于 iOS   |  
ObjectiveC Runtime的对象模型及各种runtime技术的实现原理
阅读全文 »

基于Github托管的Octopress个人博客

发表于 2014-03-25   |   分类于 Octopress   |  

Github Pages 一直是自己喜爱的博客形式,之前托管了一个简单的英文博客,直接将博客的源代码放在username.github.io项目下,
代码管理简单,但是需要github在访问时将Jeklly转换为静态的网页,未免会带来网站性能的损失。Octopress 提供了更好的管理博客的方法,并集成了更多可以使用的插件和自动化的功能,这个中文博客就是基于Octopress,仍然托管在Github上,不过不是以个人网页的形式,而是以project pages的形式托管.

在部署octopress的时候,会遇到不少问题,这里主要来记录一下,以备以后使用.

####fatal:remote origin already exists ####
我的配置环境为reby 1.9.3, 在根据Octopress的官方文档安装主题之后,并在github上建立好新的repository之后,执行rake setup_github_pages会出错,提示

remote origin already exists

解决方法:将Octopress/Rakefile中357行

git remote add origin #{repo_url} 改为 git remote set-url origin #{repo_url}

####修改相应的配置文件####
由于现在的中文博客是放在github的一个project上,目的是为了实现如下方式访问:username.github.io/project,所以我们需要修改一下Octopress的配置文件,来指明目录结构。

  • _config.yml:修改url,root,destination
  • config.rb:修改http_path,http_image_path,http_fonts_path,css_dir

具体的改变可以参考这里相对应的文件。

####UTF-8或者GB2312编码问题####
在执行rake generate命令之后,如果遇到 invalid byte sequence UTF-8 等错误,说明在你的文件当中有非法的编码字符,这些字符可能是由于我们使用的编辑器默认添加的一些字符,这里我们首先推荐使用nodepad++或者markdown专用的编辑器。

解决方法:

  • 修改Ruby193\lib\ruby\gems\1.9.1\gems\jekyll-0.12.1\lib\jekyll\convertible.rb, 改变如下
1
self.content = File.read(File.join(base, name),:encoding=>"utf-8")
  • 利用nodepad++找出非法字符,并将文档编码设置为utf-8 without BOM

上面基本上列出了我在搭建过程中遇到的问题,喜欢用github搭建博客的都起码有一些编程能力,相信大家应该都可以很好地解决这些基本的问题,也欢迎大家反映自己遇到的问题,我们一起讨论解决。

再一次感谢Github提供了如此简单,可靠,关键还是免费的搭建博客的支持:)

Debug android using WIFI without USB

发表于 2014-02-28   |   分类于 Android   |  

Here is a useful trick when you need to debug android app with out connnecting to USB, maybe you have limited USB ports or you don’t want to see so many wires in front of you.
Required:

  • WIFI environment, make sure your android device and your PC is in the same WLAN
  • of course one android device, but no root is ok

Steps:

1.connect your device with USB and open debug option
2.open a terminal and use adb tcpip 5555
3.adb connect *.*.*.*:5555 //* stands for ip of your device
4.you can disconnect usb and start wireless debug now
5.use adb usb to end wireless debug.

Wish this helpful!

iOS Concurrent Programming:NSOperationQueue

发表于 2014-02-15   |   分类于 iOS   |  

In the last article, we learned GCD, one of the most popular and convinent concurrent framework of iOS, here we will learn NSOperationQueue, which is another concurrent api you could use, also it has some difference with GCD. In the sample project, I also gave examples of working with NSOperationQueue, you can downlaod the project source code for detail.

We already know that , it is not easy to control operations added to a dispatch queue, that is you can not cancel an operation which is already added to a dispatch queue(or there is not an easy way to do this). But NSOperationQueue supports this cancel task, this is the biggest difference between them.

阅读全文 »

iOS Concurrent Programming:GCD

发表于 2013-12-29   |   分类于 iOS   |  

Concurrency is important in iOS apps, you should use concurrent api when you want some tasks running parallelly, or you want to do task in background thread in order not to block your UI thread. IOS provides us several kinds of concurrent api, like Thread, Grand central dispatch (GCD) and NSOperationQueue. Instead of using NSThread, we should always choose GCD or NSOperationQueue, for GCD and NSOperationQueue, OS will optimize the number of threads according to current state of the System. If there are already enough threads in the system, OS can decrease parallel threads managed in the thread pool of GCD and NSOperationQueue and avoid extra threads taking too much memory. In my recent work, I solved some concurrent programming issue, and want to summize my knowledge about GCD and NSOperationQueue, I also wrote an simple project, which demostrate basic usage of these concurrent api, you can downlaod the project source code for detail.

Dispatch Queue is very convinent to use, and ios exposes five different kinds of dispatch queues:three background queue with different priorities(low, normal, high),which are all concurrent queue, main queue running on main thread, and one background queue used for I/O operation. You can also create your own serial queue or concurrent queue as you needed.

Dispatch Queue

If you need to perform some task on background queue, it recommended to use system provided queues. With the api below

dispatch_queue_t dispatch_get_global_queue( long priority, unsigned long flags)

If you want to create queue yourself, you can use dispatch_queue_create and pass one string to label this queue, and DISPATCH_QUEUE_CONCURRENT or DISPATCH_QUEUE_SERIAL to indicate the type of this queue.

After get the handle of the queue, you need to add your block to this queue with
dispatch_async or dispatch_sync method, and then your block will start run at a proper time managed by the system.
After we add blocks to the queue, we have no control over the block any more, there is no api for you to cancel the operation in the queue or to the state of the operation in the queue(If you want these, you may refer to NSOperationQueue, which will be introduced in next article).

#####Resource protection for multiple thread
Because of the concurrency of blocks in dispatch queue, we need to protect our resource if it is written in the blocks, and dispatch_barrier_async is a good helper. Look at the code below:

1
2
3
4
5
6
7
8
dispatch_queue_t queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
//if we want to add an item to array
- (void)insertString:(NSString*)str
{
dispatch_barrier_async(queue, ^{
[self.array addObject:str];
});
}


With the code above, all insert operation is safe, below the addObject block will be executed when all blocks in the queue before it are completed.(Maybe this example is meaningless, it’s just a example).
阅读全文 »

Android Navigation Drawer

发表于 2013-11-23   |   分类于 Android   |  

Navigation Drawer is widely used now after Google officially support it in android support library. Apps like Gmail and Youtube also use this design, and it’s really more convinent to put navigation items in navigation drawer than in a Tab control, and this design will also make the visible size of your app much larger. I have used navigation drawer in the demo code for ExpandableListView here. It’s very simple, you can download and learn how we can use navigation drawer.

To use navigation drawer in your app, you just need the steps below:

  • first you need to declear DrawerLayout as the root container of you layout
  • the first child of DrawerLayout is the main container of your app, usually it’s a kind of viewGroup.
  • the second child of DrawerLayout is a ListView, which is used for place navigation items.

Below is a the layout we use in the demo:

阅读全文 »
12345
Charles

Charles

41 日志
5 分类
52 标签
© 2016 Charles
由 Hexo 强力驱动
主题 - NexT.Pisces