自动释放内存的保护类
- 2012年3月11日
- 程序设计
- 没有评论
-
#include <iostream> using namespace std; template class PtrGuard { public: PtrGuard(T* &p):m_p(p){}; ~PtrGuard() { if (NULL != m_p) { delete m_p; m_p = NULL; } } private: //禁止拷贝构造和赋值操作 PtrGuard(const PtrGuard&); PtrGuard& operator=(const PtrGuard&); private: T* &m_p; }; class TestClass { private: int m_i; char m_c; }; int main(int argc, char* argv[]) { TestClass* p = new TestClass; if (NULL == p) { cout << "new msg error." << endl; return -1; } // 通过PtrGuard类实现各个分支自动释放内存 PtrGuard g(p); if (true/*XXX*/) { //自动释放内存 return -1; } if (true/*XXX*/) { //自动释放内存 return -1; } return 0; }
自动编译的Makefile文件
- 2012年2月21日
- 程序设计
- 没有评论
-
“=”与“:=”的区别:“=”会递归展开,而“:=”只展开一次。
此makefile可以自动装src目录及各个子目录下的所有cpp文件,自动编译生成对应的obj文件,存放在obj目录下。最后链接成最终的二进制。目录结构如下:./src —- 源文件,可以嵌套子目录./inc —- 头文件./lib —- 库文件
./obj —- 此目录由makefile自动生成.根据源文件目录,生成完全一样的嵌套子目录.
ptool —- 此项目编译产生的最终二进制
# 最终输出的二进制名称 APP_NAME=ptool SRC_DIR=src INC_DIR=inc OBJ_DIR=obj LIB_DIR=lib SRC_SUFFIX=cpp OBJ_SUFFIX=obj CFALGS=-g -Wall FIND_PATH=-I${INC_DIR} #LIBS=${LIB_DIR}/lib.a LIBS=-lpthread # $@表示目标, $<表示依赖项 COMPILE_FILE=g++ ${CFALGS} ${FIND_PATH} -c -o $@ $< LD_FILE=g++ -o $@ ${APP_OBJS} ${LIBS} # shell表示执行后面的shell命令 APP_SRCS=${shell find ${SRC_DIR} -name *.${SRC_SUFFIX}} # 如果不需要自动加入src目录下的所有.cpp,则通过如下方式指定 #APP_SRCS=main.cpp \ # test/hello.cpp # make不带目标名时,默认为make第1个目录 all: clean dir ${APP_NAME} # 查询出src下的所有目录 SUB_DIRS:=${shell find ${SRC_DIR} -type d} # 把src/****替换为obj/**** SUB_DIRS:=${SUB_DIRS:${SRC_DIR}%=${OBJ_DIR}%} # 创建各个子目录 dir: for val in ${SUB_DIRS}; do \ mkdir -p $${val}; \ done # 把src/***/**.cpp替代为src/***/**.obj APP_OBJS:=${APP_SRCS:%.${SRC_SUFFIX}=%.${OBJ_SUFFIX}} # 把src/***/**.obj替代为obj/***/**.obj APP_OBJS:=${APP_OBJS:${SRC_DIR}/%=${OBJ_DIR}/%} ${APP_NAME}: ${APP_OBJS} ${LD_FILE} ${OBJ_DIR}/%.${OBJ_SUFFIX}: ${SRC_DIR}/%.${SRC_SUFFIX} ${COMPILE_FILE} clean: -rm -rf ${APP_OBJS} -rm -rf ${APP_NAME} -rm -rf ${OBJ_DIR} # 伪目标,表示all clean dir不是文件,不需要检查文件时间戳 .PHONY: all clean dir
C++操作符重载设计原则
- 2011年12月23日
- 程序设计
- 没有评论
-
基本原则:对于修改类对象的操作,应设计成成员函数。反之,则设计成非成员函数。
具体原则:
1、应定义为成员函数的操作符:
(1)赋值操作符(=)
(2)复合赋值操作符(+=)
(3)下标操作符([])
(4)调用操作符(())
(5)成员箭头操作符(->)
(6)自增操作符(++)
(7)自减操作符(—)
(8)解引用操作符(*)2、应定义为非成员函数的操作符:
(1)算术操作符(+,-,*,/)
(2)关系操作符(>,<,==,!=),含相等和不等
(3)移位操作符(<<,>>)3、不宜重载的操作符:
(1)取地址操作符(&)
(2)逗号操作符(,)
(3)逻辑与操作符(&&)
(4)逻辑或操作符(||)4、其他:
(1)关联容器中的元素最好定义小于号操作符(<),因为关联容器中经常需要使用此操作符进行排序。比如:std:set、std:map。
(2)顺序容器中的元素最好定义相等(==)、小于号操作符(<)。 - C++
自己实现C++引用计数
- 2011年12月22日
- 程序设计
- 没有评论
-
#include
#include class MyString { friend std::ostream& operator<<(std::ostream& os, const MyString& str); public: MyString(char* pData):m_pData(new char[strlen(pData) + 1]), m_pRefCnt(new int(1)) { strcpy(m_pData, pData); } MyString(const MyString& rhs) { this->m_pData = rhs.m_pData; m_pRefCnt = rhs.m_pRefCnt; ++(*m_pRefCnt); } ~MyString() { --(*m_pRefCnt); if (0 == (*m_pRefCnt)) { if (NULL != m_pData) { delete[] m_pData; m_pData = NULL; } if (NULL != m_pRefCnt) { delete m_pRefCnt; m_pRefCnt = NULL; } } } MyString& operator=(const MyString& rhs) { this->m_pData = rhs.m_pData; this->m_pRefCnt = rhs.m_pRefCnt; ++(*m_pRefCnt); return *this; } char& operator[](int iIndex) { /// 有其他对象引用 if ((*m_pRefCnt) > 1) { char* pPrevData = m_pData; m_pData = new char[strlen(pPrevData) + 1]; strcpy(m_pData, pPrevData); int* pPrevRefCnt = m_pRefCnt; --(*pPrevRefCnt); m_pRefCnt = new int(1); } return m_pData[iIndex]; } const char* c_str() { return m_pData; } private: MyString(); private: char *m_pData; int* m_pRefCnt; }; std::ostream& operator<<(std::ostream& os, const MyString& str) { os << str.m_pData; return os; } int main(int argc, char* argv) { MyString str1 = "abc"; MyString str2 = str1; MyString str3 = str1; std::cout << "str1:" << str1 << " addr:" << std::hex << (void *)str1.c_str() << std::endl; std::cout << "str2:" << str2 << " addr:" << std::hex << (void *)str2.c_str() << std::endl; std::cout << "str3:" << str3 << " addr:" << std::hex << (void *)str3.c_str() << std::endl; str1[1] = '0'; std::cout << std::endl; std::cout << "str1:" << str1 << " addr:" << std::hex << (void *)str1.c_str() << std::endl; std::cout << "str2:" << str2 << " addr:" << std::hex << (void *)str2.c_str() << std::endl; std::cout << "str3:" << str3 << " addr:" << std::hex << (void *)str3.c_str() << std::endl; str1[1] = '-'; std::cout << std::endl; std::cout << "str1:" << str1 << " addr:" << std::hex << (void *)str1.c_str() << std::endl; std::cout << "str2:" << str2 << " addr:" << std::hex << (void *)str2.c_str() << std::endl; std::cout << "str3:" << str3 << " addr:" << std::hex << (void *)str3.c_str() << std::endl; str2[1] = '='; std::cout << std::endl; std::cout << "str1:" << str1 << " addr:" << std::hex << (void *)str1.c_str() << std::endl; std::cout << "str2:" << str2 << " addr:" << std::hex << (void *)str2.c_str() << std::endl; std::cout << "str3:" << str3 << " addr:" << std::hex << (void *)str3.c_str() << std::endl; return 0; } - C++
基于引用计数的STL string使用注意事项
- 2011年12月22日
- 程序设计
- 没有评论
-
注意:经测试,Windows的STL string实现未使用引用计数。以下讨论仅针对Linux而言。
1、 string使用引用计数提升效率
为提升效率,string内部使用引用计数。每次string进行复制时,并不重新new一片内存,复制一份新的字符串。而是共享一份字符串。
举例:
#include <string> #include <iostream> using namespace std; int main(int argc, char* argv) { string str1 = "abcd"; string str2 = str1; string str3 = str1; cout << "str1:" << str1 << " address:" << hex << (void *)str1.c_str() << endl; cout << "str2:" << str2 << " address:" << hex << (void *)str2.c_str() << endl; cout << "str3:" << str3 << " address:" << hex << (void *)str3.c_str() << endl; return 0; }输出:
KEN:~/test # ./a.out str1:abcd address:0x804a014 str2:abcd address:0x804a014 str3:abcd address:0x804a014 KEN:~/test
从输出可以看到,3个string的内容相同,其中的指针指向同一片内存区域。
2、强制修改string的内容影响其他string
使用引用计数后,因多个string指向同一块内存区域。因此,如果强制修改一个string的内容,会影响其他string。
举例:
#include <string> #include <iostream> using namespace std; int main(int argc, char* argv) { string str1 = "abcd"; string str2 = str1; string str3 = str1; cout << "str1:" << str1 << " address:" << hex << (void *)str1.c_str() << endl; cout << "str2:" << str2 << " address:" << hex << (void *)str2.c_str() << endl; cout << "str3:" << str3 << " address:" << hex << (void *)str3.c_str() << endl; char* pBuf = (char*)str1.c_str(); pBuf[2] = '-'; cout << "str1:" << str1 << " address:" << hex << (void *)str1.c_str() << endl; cout << "str2:" << str2 << " address:" << hex << (void *)str2.c_str() << endl; cout << "str3:" << str3 << " address:" << hex << (void *)str3.c_str() << endl; return 0; }输出:
KEN:~/test # ./a.out str1:abcd address:0x804b014 str2:abcd address:0x804b014 str3:abcd address:0x804b014 str1:ab-d address:0x804b014 str2:ab-d address:0x804b014 str3:ab-d address:0x804b014 KEN:~/test #
从输出可以看到,强制修改一个string的内容后,其他string的内容也受影响。
3、使用string提供的接口操作字符串可以避免影响其他string
string对[]操作符和at()方法进行了特殊处理。当使用[]操作符/at()方法修改string中的内容时,如果string有其他string跟其指向同一个字符串,则string将重新new一片内存区域,以此避免影响其他string。
举例:
#include <string> #include <iostream> using namespace std; int main(int argc, char* argv) { string str1 = "abcd"; string str2 = str1; string str3 = str1; cout << "str1:" << str1 << " address:" << hex << (void *)str1.c_str() << endl; cout << "str2:" << str2 << " address:" << hex << (void *)str2.c_str() << endl; cout << "str3:" << str3 << " address:" << hex << (void *)str3.c_str() << endl; str1[2] = '-'; cout << "str1:" << str1 << " address:" << hex << (void *)str1.c_str() << endl; cout << "str2:" << str2 << " address:" << hex << (void *)str2.c_str() << endl; cout << "str3:" << str3 << " address:" << hex << (void *)str3.c_str() << endl; return 0; }输出:
KEN:~/test # ./a.out str1:abcd address:0x804b014 str2:abcd address:0x804b014 str3:abcd address:0x804b014 str1:ab-d address:0x804b02c str2:abcd address:0x804b014 str3:abcd address:0x804b014 KEN:~/test #
从输出可以看到,使用string的[]操作符修改一个string的内容后,其他string的内容不受影响。
4、 结论
对string的内容进行操作时,应避免强制修改其中的内容。而应使用string提供的[]操作符和at()方法。
Visual Assist X 快捷键
- 2011年12月17日
- 程序设计
- 没有评论
-
VAX 10.6:
Alt+O OpenCurrespondingFile .h/.cpp切换
Alt+G GotoImplementation 调到实现
Alt+M ListMethodsInCurrentFileShift+Alt+F Find References 查找引用
Shift+Alt+S FindSynbolDialog 打开查找符号对话框Alt+Left Arrow NavigateBack 后台
Shift+Alt+O OpenFileInSolutionDialog 打开解决方案文件对话框
Ctrl+Shift+V Parse 弹出最近10个copy的内容菜单
Shift+Alt+Q RefactorContextMenu 弹出重构菜单
Shift+Alt+C RefactorCreateFromUsage
Shift+Alt+R RefactorRename 改名
Alt+Down Arraw ScopeNext
Alt+Up Arraw ScopePrevious
类设计思路
- 2011年9月16日
- 程序设计
- 没有评论
-
1、找出所有子类的共用行为。
以此作为基类的方法。
2、找出哪些共用行为与型别相关。
与型别相关的方法应该设计成虚方法。
3、识别出各方法的存取层级(private、protected、public)
vi常用技巧
- 2011年9月9日
- 操作系统
- 没有评论
-
1、在每行行首/行尾插入相同字符:%s/^/your_word/ :%s/$/your_word/ 比如:
#所有行首加# :%s/^/#/g #2~5行行尾加// :2,5s/$/\/\//g
2、不熟悉的项
cw→ 替换光标所在位置的一个单词^→ 到本行第一个不是blank字符的位置(所谓blank字符就是空格,tab,换行,回车等)g_→ 到本行最后一个不是blank字符的位置。<C-r>→ redo:e <path/to/file>→ 打开一个文件:bn和:bp→ 你可以同时打开很多文件,使用这两个命令来切换下一个或上一个文件。3p→ 粘贴文本3次3.→ 重复 3 次w→ 到下一个单词的开头。e→ 到下一个单词的结尾。3、显示vim配置文件路径:
:set runtimepath
VC2005常用技巧
- 2011年9月8日
- 程序设计
- 没有评论
-
1、显示行号
工具–选项–文本编辑器(TextEditor)–C++–常规,显示(Display)–”行号”(Line Numbers)2、高亮当前光标下变量的引用
VC助手配置–Adavanced–Refactoring–Automatically highlight references to symbol under cursor3、让VC自动联想Linux库函数
(1)将Linux的/usr/include目录下的所有文件,copy到Windows的某个目录下
(2)将此目录设置为VC工程Include目录:
Project–XXXXX properties–Configuration Properties–C/C++–General–Additional Include Directories
(3)让VC助手解析这些头文件:
进入VX(VC助手)的选项界面:VAssistX=>Visual Assist X Options=>Peformence=>Rebuild(sambol databases)
近期评论