zoukankan      html  css  js  c++  java
  • C++ Project 积累(3)

    1. 头文件重复引用

    强行将涉及文件操作都放在 my_file_system.h/.cpp , 导致出现了需要头文件相互引用的局面, 具体来说

    有两个头文件和源文件, 分别是 h1.h, h1.cpp, h2.h, h2.cpp. h2.h include "h1.h" 并定义了 class C2. 同时, h1 中需要使用 C2 的实例, 最后发现 C2 h1 中是不完整的类型, 不能直接调用其函数和类内变量. 即便是使用前置声明, 无法调用实例的变量和函数也使其用处有限.

    搜了下, exception c++ 中有所阐述:

    第一个原则应该是,如果可以不包含头文件,那就不要包含了。这时候前置声明可以解决问题。如果使用的仅仅是一个类的指针,没有使用这个类的具体对象(非指针),也没有访问到类的具体成员,那么前置声明就可以了。因为指针这一数据类型的大小是特定的,编译器可以获知。

    第二个原则应该是,尽量在CPP文件中包含头文件,而非在头文件中。假设类A的一个成员是是一个指向类B的指针,在类A的头文件中使用了类B的前置声明并便宜成功,那么在A的实现中我们需要访问B的具体成员,因此需要包含头文件,那么我们应该在类A的实现部分(CPP文件)包含类B的头文件而非声明部分(H文件)

    在这里, 有一些解释 http://patmusing.blog.163.com/blog/static/135834960201038113714199/

    但是, 这种方法有其局限性, 我实验了一下 class A class B 放到不同的头文件中, 发现调用 b->somefunc() 时仍然会报错, 说是不完整类型.

    所以, 以后设计类的时候需要仔细考虑, 不能发生头文件重复引用的问题.

     2. int main(int argc, char* argv[]) 用法

    int main(int argc, char* argv[])  {
    
    	cout << "input is: " << endl;
    
    	for(int i = 1; i < argc; i++)  {
    		printf("%s ", argv[i]);
    	}
    	cout << endl;
    	return 0;
    }
    

    在 windows 下, 输入 test from to 输出为 from to.

    argc 是参数个数, 这里为 3 个. argv[] 分别是 test from to

    3. 为了构造定制 PCAP 文件格式, 写了两个函数, 分别是 create_pcap_file 和 write_pcap_packet, 实现如下

    void create_pcap_file(const string filename, int linktype)  {
    	struct pcap_file_header fh;
        fh.magic = 0xa1b2c3d4;
        fh.sigfigs = 0;
        fh.version_major = 2;
        fh.version_minor = 4;
        fh.snaplen = (1<<16)-1; 
        fh.thiszone = 0;
        fh.linktype = linktype;
    
        FILE *file = fopen(filename.c_str(), "wb");
        if(file != NULL) {
            if(fwrite(&fh, sizeof(fh), 1, file) != 1) {
                fclose(file);
                file = NULL;
            }  else  {
    			fclose(file);
    			file = NULL;
    		}
        }
    }
    
    int write_pcap_packet(FILE* file,const pcap_pkthdr *header, const unsigned char *data, size_t length)  {
    	
    	if(fwrite(header, sizeof(pcap_pkthdr), 1, file) != 1) {
            return 1;
        }
    	
        if(fwrite(data, 1, length, file) != length) {
            return 2;
        }
    	
        return 0;
    }
    

    我需要考虑多台机器上同时处理文件最后再将中间结果合并, 而 Pcap 文件的描述只能在文件的开头且只能出现一次, 所以合并文件的时候难免要加上一些判断语句.

    今天我突然想到, Pcap 文件描述在每个文件中出现一次且内容都相同, 因此可以直接把包流写到文件中, 文件 merge 之后再统一加上文件描述

    这就需要 fseek 函数, cplusplus 中关于 fseek 的解释

    int fseek ( FILE * stream, long int offset, int origin );
    #include <stdio.h>
    
    int main ()
    {
      FILE * pFile;
      pFile = fopen ( "example.txt" , "wb" );
      fputs ( "This is an apple." , pFile );
      fseek ( pFile , 9 , SEEK_SET );
      fputs ( " sam" , pFile );
      fclose ( pFile );
      return 0;
    }

     其中, SEEK_SET 是 beginning of file, 可选的参数还有 SEEK_CUR(current position of file) 和 SEEK_END(end of file)

    4. python 处理文件

    未来会用到多文件 merge 操作, 用 python 操作会比较简单, 为此我总结了一下

    http://app.yinxiang.com/shard/s9/sh/3b6fffb7-e08e-4176-bc67-3b633f9ef0f2/2d6137381f8d4fdc72eb96a4b86454fc

    http://app.yinxiang.com/shard/s9/sh/525cdfba-f487-400d-9eac-a72b33093897/18d37aa66c53f3c999af510c4a15e415

    另外, python 还支持 copy *.txt out.txt 操作

    5. 文件的处理速度对比

    5.1 每次读出一个包, 处理并写入

    5.2 每次读入一个 190M 文件, 处理并写入

    5.3 使用多线程的生产者消费者算法, 创建 buffer, 读入与写入同时进行

    6. 深 copy 和 浅 copy

    stackoverflow 一个回答: http://stackoverflow.com/questions/1474618/c-programming-how-to-deep-copy-a-struct

    我创建了个 class 专门用于存储从 disk 中读取的数据, 类的定义如下

    class PcapPacket {
    public:
    	PcapPacket(const pcap_pkthdr* _header, const u_char* _data, size_t _length)  {
    		header = _header;
    		data = _data;
    		length = _length;
    	}
    	PcapPacket()  {
    		header = NULL;
    		data  = NULL;
    		length = 0;
    	}
    	~PcapPacket()  {
    		
    	}
    public:
    	const pcap_pkthdr* header;
    	const u_char *data;
    	size_t length;
    };
    

    类实例的创建

    7. 动态创建数组

    	int *data = new int[n];
    	cout << sizeof(data) << endl;
    	memset(data, 0, sizeof(data));
    

    想了半天, 没搞懂 memset 为什么不起作用, 最后才明白过来, sizeof(data) 是 4

    可见, 书上的知识和应用还是有段距离

    memset(data, 0, n*sizeof(data)); // corrent
    

    8. 减少内存拷贝的一个方法

    class A;
    A a;
    vector<A> vec;
    vec.push_back(a);
    

    上面代码是为了向 vec 中添加一个值, 这其中构造函数调用两次, 析构函数调用一次(另一次最终还是需要被调用)

    假设创建 A 的实例需要申请很多空间, 那么就会发生很多内存的拷贝. 这是很不利的

    我的一个解法, 将 a 的初始化提取出来, 将 a 加入到 vec 中再正常实例化

    upstream_traffic[jac_name].push_back(PcapPacket(header, data, header->len));
    
     downstream_traffic[jac_name].push_back(PcapPacket());
    			 downstream_traffic[jac_name].back().init(header, data, header->len);// error
    

    push_back 会发生拷贝构造函数, 使用 init 的话, 我们可以将拷贝构造函数和复制构造函数写的尽可能的简单

  • 相关阅读:
    redis>lua脚本
    redis百万级数据存取
    spring之自定义注解
    spring>aop
    git的回退和撤销操作
    vue2.0 v-tap简洁(漏)版 (只解决300ms问题)
    JSONP原理小记
    前端模块加载规范AMD与CMD小记
    html状态码
    使用vue-cli开发时跨域问题
  • 原文地址:https://www.cnblogs.com/zhouzhuo/p/3690785.html
Copyright © 2011-2022 走看看