zoukankan      html  css  js  c++  java
  • c++ 基础知识回顾

    1.数据类型和类。

    所有编程都是处理输入和输出。

    关于输入参数,从右至左把参数入栈,这样根据栈基址,可以定位第一个参数。因为很多函数是参数数量不定的,比如printf.

    关于输出,记得输出时,一般是把值放入eax 寄存器,

      所以一般数据类型,直接放入返回值数据,寄存器可以装下,

      而返回对象,会返回对象的指针,并在调用者的栈中,按位复制。之后清栈

      而返回指针,会把指针放入寄存器,之后清栈。

    所以第一条守则:不要返回或传参为函数局部对象的指针,而是返回局部对象或堆中地址。

    隐藏守则:如果是返回一个集合,如vector<>,而里面是指针,就相当于返回了局部对象的指针。

    所以最佳实践:

    函数中:

    对象的创建,必须明确,仅仅是局部使用,还是会传出去,局部使用,就可以直接在栈中,如果会传出去(或返回,或包含在返回对象中,或作为参数),必须传递对象,或者堆中的地址(智能指针)

    就算是主函数中,不会清栈的情况下。还是为了语义的正确和统一性已经性能,也必须在堆中申请。

    类中:

    如果是类中的变量,自己new 了,必须自己delete .如果是指针,由外部传入,那么必须使用智能指针(因为你不确定使用者何时会delete)

    一句话,除考虑性能之外,判断是否new,看变量的生存期是本函数,还是超过本函数。

    考虑性能,可以对于生存期在本函数类的变量。new 之后再 delete.极端情况是个大数据,而中间还要调用很深的栈。

    非常明确的局部使用小对象,小数据,不需要new.否则智能指针吧。

    当然根据 raii,用类管理资源的守则,应该写成用类管理资源。

    但是默认的复制构造函数是按位复制。所以会出现2次析构。导致错误。

    所以1,自定义复制构造函数。

     2,使用智能指针。

    使用智能指针,就为我们定义了一个根据引数进行的析构函数,只有当引数为0才进行delete 操作。

    使用智能指针,就要说到为什么使用指针。必须要使用指针的场合,自己好像只碰到过的,只有在继承场合下。而且此指针需要传递给外部。否则可以局部对象,加&。

    所以准则2:当由于继承或其他情况下需要使用指针时,使用智能指针代替原指针。用智能指针这个模板类来管理资源。


    再返回去说数据。基本数据没什么好说。int,char,都是定死的资源。对于c来说。使用指针感觉就是为了char *.字符串。

    类,只包含基本类型。也没什么好说。复制是成员数据类型按位复制,

    如果类包含另外一个类的对象。那么1,为了节省栈空间。可以只包含类的指针。2,同一个对象会被不同的类包含,那么必须使用指针就节省了整个内存。

    使用指针,当然就是用智能指针,省去自己处理拷贝构造函数的编写。

    根据准则一,不要返回局部变量的指针,我们可以返回局部变量,而继承必须使用指针来表示。所以有一种必须使用new  的场合,就是返回包含派生类指针的集合。

    所以目前总结,适合使用到智能指针(指针)的场合:1.继承,2。某个类的对象,会被多个另外不同的对象包含。3.需要作为返回值,而为了性能,可以返回堆中的地址(智能指针)4.容器包含指针,而且作为返回值,必须在堆中new.

    所以准则3:

    不考虑性能问题,必须使用new,就1种情况,需要返回派生类指针的集合,如 vector<base *> fun (); 那么必须在函数中用new;

    考虑性能,使用new,多3种情况。1.返回智能指针,而不是类对象。2.某个类的对象,会被另外类的多个不同的对象包含,那么复合类,采用智能指针,3某个类的成员是个大数据,比如缓存类,必须使用new到堆中,栈放不下。以免使用者,直接

    在栈中生成对象。

    而使用指针在上面的情况外。就是继承。

    2.再谈输入与输出。

    所以综合考虑,写函数。除非性能和栈空间的考虑,基本可以不用到new .除非需要返回派生类指针的集合

    而使用指针也很有限。1.就是为了多态,使用指针。2.传递指针给函数,函数需要修改数据。

    3构造和析构

    如上所诉,类中需要使用智能指针成员,就是1,为了多态。2为了性能。

    感觉不如用function.

    构造函数中不能调用基类的虚构造。

    析构函数不让异常逃出。

     基类必须实现虚析构。

    5.资源管理

    6.一般实践:

    函数内部变量:

    1.非常明确的局部变量(不返回,不作为参数)的小数据,用对象,不需要new.

    2.否则智能指针吧。

    函数参数和返回值:

    1.不需要修改那么const ref

    2.如要修改用原始指针

    3.返回必定智能指针(google 的硬性规定就是指针,好像不推荐返回对象)

    见例子,非常实用的干货。

    作者:陈硕
    链接:https://www.zhihu.com/question/22821303/answer/22759540
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    class Request : boost::noncopyable { /* ... */ };
    class Buffer { /* network I/O buffer */ };
    
    // return unique_ptr means caller taking ownership
    std::unique_ptr<Request> parseRequest(Buffer* inputMessage)
    {
      std::unique_ptr<Request> req(new Request); // make_unique<Request>() in C++14
      // fill in req with inputMessage
      return std::move(req);
    }
    
    // pass unique_ptr means callee taking ownership
    void processRequest(std::unique_ptr<Request> req)
    { /* may process in a different thread, taking ownership of req */ }
    
    // pass raw pointer means changing it but not taking ownership
    void augmentRequest(Request* req)
    { /* fill in more fields, but not keeping the pointer longer than 
         the scope of this function. */ }
    
    // pass const reference means read it but not taking ownership
    bool validateRequest(const Request& req)
    { /* do not keep the pointer or reference outside this function. */ }
    
    void onNetworkMessage(Buffer* inputMessage)
    {
      std::unique_ptr<Request> req = parseRequest(inputMessage);
      augmentRequest(req.get());
      if (validateRequest(*req)) {
        processRequest(std::move(req));
      }
    }

    类内部变量:

    以下3种情况有智能指针,或者引用。否则直接对象。

    1)多态必须指针,就智能指针
    2)可能和别的类共享,或者只是引用某个对象,所以生命周期不是很确定(考虑智能指针)

    就比如lock_gurad ,锁类,里面的互斥锁mutex ,必须是外部对象引用(stl里面放入的是引用)。 智能锁类,不管理锁本身内存,只关注锁的锁定和放锁。

    #include <iostream>
    #include "stdio.h"
    #include <memory>
    #include <unistd.h>
    #include <thread>
    #include <vector>
    #include <mutex>
    #include <unistd.h>
    #include <stdlib.h>
    
    using namespace std;
    
    mutex mtx;
    
    class mylock_guard
    {
    public:
        mylock_guard(mutex& _mtx):mtx(_mtx)
        {
            mtx.lock();
        }
        
        ~mylock_guard()
        {
            mtx.unlock();
        }
        
    private:
        mylock_guard(const mylock_guard&);
        mylock_guard& operator=(const mylock_guard&);
        mutex& mtx;
    };
    
    
    void ShowMsg()
    {
        //lock_guard<mutex> lck(mtx);
        mylock_guard lck(mtx);
        cout<<"1 seconed"<<endl;
        sleep(1);
    }
    
    int main()
    {
        
        thread t1(ShowMsg);
        thread t2(ShowMsg);
        thread t3(ShowMsg);
        
        t1.detach();
        t2.detach();
        t3.detach();
        
        string cmd;
        cin>>cmd;
    }

    3)大数据,如果定义成对象,会导致当前对象无法在栈内创建

  • 相关阅读:
    oracle 导入数据时提示只有 DBA 才能导入由其他 DBA 导出的文件
    oracle 常用语句
    android udp 无法收到数据 (模拟器中)
    android DatagramSocket send 发送数据出错
    AtCoder ABC 128E Roadwork
    AtCoder ABC 128D equeue
    AtCoder ABC 127F Absolute Minima
    AtCoder ABC 127E Cell Distance
    CodeForces 1166E The LCMs Must be Large
    CodeForces 1166D Cute Sequences
  • 原文地址:https://www.cnblogs.com/lsfv/p/6677947.html
Copyright © 2011-2022 走看看