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)大数据,如果定义成对象,会导致当前对象无法在栈内创建

原文地址:https://www.cnblogs.com/lsfv/p/6677947.html