《白话C++》代码精选合集(不全,慢慢补充)

第7章 语言

7.3.7  转移行为

         转移构造,转移构造的目的在于独占(霸占)源对象中指针成员所指向的内存,所以它要求源对象(例中的other)“签字画押”,白纸黑字地表明“是我自愿放弃我的堆成员所占的内存,并将其所有权转移给新对象,我自愿让我的堆成员回归为空指向”。

#include <iostream>
 
using namespace std;
 
struct MyPtr
{
    explicit MyPtr(int value)
        : ptr(new int(value))
    {
        cout << "调用了" << __func__ << "的入参构造"
             << ",入参是:" << value << endl;
    }
    ~MyPtr()
    {
        delete ptr;
    }
    //禁止复制构造和复制赋值,复制构造和复制赋值,需要保持源对象不变,所以参数需要使用const修饰
    MyPtr(MyPtr const& other) = delete; //禁止复制构造
    MyPtr& operator = (MyPtr const& other) = delete; //禁止复制赋值
    //转移构造,转移构造的目的在于独占(霸占)源对象中指针成员所指向的内存,所以它要求源对象(例中的
    //other)“签字画押”,白纸黑字地表明“是我自愿放弃我的堆成员所占的内存,并将其所有权转移给新对象,
    //我自愿让我的堆成员回归为空指向”。
    MyPtr(MyPtr&& other) //参数没有const修饰,&&是右值引用
        : ptr(other.ptr)
    {
        cout << "调用了" << __func__ << "的转移构造" << endl;
        other.ptr = nullptr;
    }
    //转移赋值
    MyPtr& operator = (MyPtr&& other) //参数没有const修饰,&&是右值引用
    {
        cout << "调用了" << __func__ << "的转移赋值" << endl;
        if(ptr != other.ptr)
        {
            ptr = other.ptr;
            other.ptr = nullptr;
        }
        return * this;
    }
    //友元,重写 << 符,用于输出
    friend ostream& operator << (ostream& os, MyPtr& mp)
    {
        os << "得到的MyPtr对象的ptr指向:" << mp.ptr
           << "  值为:" << *mp.ptr << endl;
 
        return os;
    }
 
    int * ptr;
};
 
int main()
{
    MyPtr mip(5);
    cout << mip;
    cout << "------------1------------" << endl;
    MyPtr mip_2(10);
    cout << mip_2;
 
    cout << "---------转移之后----------" << endl;
    //使用转移构造,创建mip_3对象,mip_3将抢夺mip的ptr成员
    //将mip强制类型转换为MyPtr&&类型,下面的代码才会是转移构造
    MyPtr mip_3(static_cast<MyPtr&&>(mip));
    cout << mip_3;
    //再查看mip的ptr成员是否变为了空
    cout << (mip.ptr == nullptr) << endl;//输出为1,mip.ptr已为空
    //此时不能直接访问mip,
 
    //为了方便输入,C++标准库提供了一个特定的move函数,用于代替"static_cast"转换
    //我们使用std::move()函数来抢夺mip_2
    cout << "使用std::move()函数来完成转移" << endl;
    MyPtr mip_4(std::move(mip_2));
    cout << mip_4;
    cout << (mip_2.ptr == nullptr) << endl;
 
    return 0;
}

运行结果为:

7.5.4 右值引用

#include <iostream>
 
using namespace std;
 
void test1()
{
    int a = 100;
    int b = 50;
    int c = a + b; //编译通过,a+b的和会先存储到一个临时对象_T_,然后再存储到c
}
 
void test2()
{
    int a = 100;
    int b = 50;
//    int& c = a + b; //编译不通过,如果通过,c处境危险。因为c和临时对象_T_是一体了,但是本体_T_很快就会消亡。
    //C++的让步的底线是:允许有名字的常量易用附体到无名的临时数据。
    int const& c = a + b; //引用c的存在将为存储“a+b”结果的临时变量_T_延续生命。
}
 
void foo(int& i) //入参是非常量引用,所以调用时不能传递表达式
{
 
}
 
void foo_c(int const& i)//入参是常量引用,它可以附体到无名的临时数据,并有效延续对方的生命周期。
{
 
}
 
void test3()
{
    int a = 100, b = 50;
//    foo(a + b); //ERROR! "a + b"计算结果天生是常量
    foo_c(a + b); //foo_c的入参是常量引用,可以附体到无名的临时数据,并有效延续对方的生命周期。
}
 
int main()
{
    cout << "Hello world!" << endl;
    return 0;
}
#include <iostream>
 
using namespace std;
 
void test1()
{
    int a = 100, b = 50;
    int&& c = a + b; //c是右值引用
    cout << "c =" << c << endl; //150
    cout << "a + b = " << a + b << endl;
    c = 99; //可以修改
    cout << "c = " << c << endl;
    cout << "a + b = " << a + b << endl;
}
int foo()
{
    return 0;
}
void test2()
{
    int a, c, c1, d;
    //右值引用,就是专门用于附体到某个右值的引用。什么叫右值,粗浅地说就是赋值操作符“=”右边的值。
    a = 10; //10此时是右值
    c = c1 + 2; //“c1 + 2”的结果此时是右值
    d = foo(); //“foo()”返回的结果此时是右值
 
    /*在函数调用时,编译器会产生某些无名的临时数据,这些数据也经常是赋值操作中的右值。
      而右值引用主要就是为这些匆匆产生又匆匆消亡的数据“续命”;更现实和残酷一点,是“夺命”或“鹊巢鸠占”,
      中性叫法是“转移(move)”。正是因为夺命,所以右值引用只能用在那些“将死”的右值上,不能用在左值身上,
      所谓左值也不一定就是赋值操作符左边的值,而是值那些独立的,有名有姓的(有变量或常量名),生命周期还
      挺长的家伙,为什么,因为人家获得好好的,不让“夺”*/
    int abc = 9;
    int&& rr1 = abc * 2; //OK “abc*2”的计算结果存储于某个无名,临时(短命)的右值上,rr1成功从该右值上抢到命,
    //int&& rr2 = abc; //ERROR  rr2却失败了,因为abc的生命周期还在(活得好好的),不允许这样被转移到rr2身上去。
}
 
int main()
{
    test1();
    return 0;
}

第13章  网络

13.6.3  实现多样化回调

1.使用自由函数或静态方法转接

这是一个带有进度显示的下载程序,其中进度显示函数,使用的是类DownloadProgress的静态成员函数 static int down_progress(void* userdata
                      , curl_off_t dltotal, curl_off_t dlnow
                      , curl_off_t ultotal, curl_off_t ulnow)

#include <curl/curl.h>
#include <iostream>
#include <fstream>
#include <sstream> //stringstream
#include <cassert>
 
using namespace std;
 
int to_size(char* data, size_t size, size_t nmemb, void* userdata)
{
    int result_code = 0;
 
    string s(data, size*nmemb);
    stringstream ss(s);
    ss >> result_code;
 
    if(!ss.bad() && result_code == 213)
    {
        int* pcode = static_cast <int*> (userdata);
        ss >> *pcode;
    }
 
    return nmemb*size;
}
 
int to_stream(char* data, size_t size, size_t nmemb, void* userdata)
{
    ostream& os = *static_cast <ostream*> (userdata);
    std::string line(data, size*nmemb);
    os << line;
    return size*nmemb;
}
 
//取FTP服务器指定文件的大小
int get_server_file_size(string const& server_url
                         , string const& username
                         , string const& password
                         , string const& pathfile)
{
    CURL* handle = curl_easy_init();
 
    curl_easy_setopt(handle, CURLOPT_URL, server_url.c_str());
    //username和password也需要C形式的字符串
    curl_easy_setopt(handle, CURLOPT_USERNAME, username.c_str());
    curl_easy_setopt(handle, CURLOPT_PASSWORD, password.c_str());
 
    string cmd = "SIZE " + pathfile; //SIZE后面要有个分号
    curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, cmd.c_str());
 
    int filesize = 0;
    curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, to_size);
    curl_easy_setopt(handle, CURLOPT_HEADERDATA, static_cast <void*> (&filesize));
    curl_easy_perform(handle);
    cout << "filesize = " << filesize << endl;
 
    curl_easy_cleanup(handle);
    return filesize;
}
 
class DownloadProgress //用于显示进度的类
{
public:
    DownloadProgress() = default;
 
    //当需要通知进度时,回调
    //将down_progress()移入DownloadProgress类,变身静态成员函数
    static int down_progress(void* userdata
                      , curl_off_t dltotal, curl_off_t dlnow
                      , curl_off_t ultotal, curl_off_t ulnow)
    {
        assert(userdata);
 
        DownloadProgress * dp = static_cast <DownloadProgress *> (userdata);
 
        if(! dp->IsStarted())
            dp->Start(dltotal);
 
        dp->OnProgress(dlnow);
 
        return 0;
    }
 
    bool IsStarted() const {return _total_bytes != 0;}
    void Start(size_t total_bytes)
    {
        _last_progress = 0;
        _total_bytes = total_bytes;
        _beg = time(nullptr);
    }
 
    int OnProgress(size_t downloaded)
    {
        if(0 == _total_bytes)
            return 0;
 
        time_t now = time(nullptr);
        double finished_ratio = (1.0 * downloaded) / _total_bytes;
        int current_progress = static_cast <int> (50 * finished_ratio); //表示进度的等号的数量
        if(_last_progress != current_progress)
        {
            cout << static_cast <int> (finished_ratio * 100) << "%";
 
            for(int i = 0; i < current_progress; ++i)
                cout << '=';
 
            double seconds = now - _beg;
            if(seconds >= 1)
            {
                double speed = downloaded/seconds/1000;
                cout << "->" << speed << "K/S";
            }
 
            cout << '\n';
            _last_progress = current_progress;
        }
 
        return 0;
    }
 
private:
    time_t _beg;
    size_t _total_bytes = 0;
    int _last_progress;
};
 
int main()
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL* handle = curl_easy_init();
 
    ofstream ofs("a.zip", ios_base::out | ios_base::binary);
    if(!ofs)
    {
        cerr << "无法打开本地文件a.zip。" << endl;
        return -1;
    }
 
    string server_url = "ftp://127.0.0.1:21/";
    string pathfile = "fengjie/meili/2.zip";
    string username = "d2school";
    string password = "123456";
 
    //取服务端指定文件大小
    size_t file_size = get_server_file_size(server_url, username, password, pathfile);
    //告诉libcurl待下载文件的总大小
    curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, static_cast <curl_off_t> (file_size));
 
    //开启进度通知
    curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
//    curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, down_progress);
    curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, DownloadProgress::down_progress);
    DownloadProgress dp;
    curl_easy_setopt(handle, CURLOPT_XFERINFODATA, static_cast <void *> (&dp));
 
    //设置如何处理下载的数据
    string url = server_url + pathfile;
    curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
//    //username和password也需要C形式的字符串
    curl_easy_setopt(handle, CURLOPT_USERNAME, username.c_str());
    curl_easy_setopt(handle, CURLOPT_PASSWORD, password.c_str());
 
    //本次下载采用直接定位到文件的方式,类似于http协议的下载,不需要使用ftp命令: RETR 文件名
    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, to_stream);
    curl_easy_setopt(handle, CURLOPT_WRITEDATA, static_cast <void*> (&ofs));
 
    curl_easy_perform(handle);//启动下载
 
    ofs.close();//流要关闭
 
    curl_easy_cleanup(handle);
    curl_global_cleanup();
 
    return 0;
}
 

2.用模板实现更强大的回调

绑定Lambda表达式

下面是《白话C++练武篇》书中658页,访问ftp服务器得到报头数据的程序

#include <curl/curl.h>
#include <iostream>
 
using namespace std;
 
size_t to_stream(char* data, size_t size, size_t nmemb, void* userdata)
{
    ostream& p = * static_cast <ostream *> (userdata);
 
    //从一个C风格的字符串构造字符串,但最多取n个字符或遇到'\0'
    std::string line(data, size*nmemb);
    //将字符串写入到指定的ostream对象中
    p << line;
 
    return size*nmemb;
}
 
int main()
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL* handle = curl_easy_init();
    string url = "ftp://d2school:123456@127.0.0.1/:21";
    curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
 
    /*在libcurl库中,CURLOPT_HEADERFUNCTION是一个选项,它允许你设置一个回调函数来处理接收到的HTTP头信息。*/
    curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, to_stream);
 
    /*libcurl常数CURLOPT_HEADERDATA是libcurl的一个选项,它用于传递指针给libcurl*/
    curl_easy_setopt(handle, CURLOPT_HEADERDATA, static_cast <void*> (&cout));
 
    curl_easy_perform(handle);
    curl_easy_cleanup(handle);
    curl_global_cleanup();
 
    return 0;
}

26行,使用to_stream函数,被设置为访问报头数据,需要的回调函数。它将访问得到的网络数据打印出来。

29行,为了将报头数据打印到控制台,将cout传递给了to_stream, 因为仅仅to_stream是不够的,还需要cout的辅助。

运行结果为。

下面我们使用模板技术实现更强大的回调方式

#include <curl/curl.h>
#include <iostream>
#include <fstream>
#include <string>
#include <functional>
 
using namespace std;
 
struct CURLFunctionHelper
{
    CURLFunctionHelper(CURL* curl, CURLoption opt_function, CURLoption opt_data)
    {
        curl_easy_setopt(curl, opt_function, inner_function);
        curl_easy_setopt(curl, opt_data, this);
    }
 
    template <typename Fn>//使用模板技术
 
    void Bind(Fn&& fn) //fn的类型是个右值
    {
        //对象fn并非简单复制给了_callback,而是转移给了_callback,即:若是fn含有指针
        //类型的成员,则指针复制给_callback, fn的指针成员被赋值为nullptr
        _callback = std::move(fn);
    }
 
private:
    //简化function类型表达
    typedef std::function <size_t(char*, size_t, size_t)> CURLCallback;
    //负责转接的静态成员函数
    static size_t inner_function(char* data
                                 , size_t size, size_t nmemb
                                 , void* userdata)
    {
        auto self = static_cast <CURLFunctionHelper*> (userdata);
        return self->_callback(data, size, nmemb); //在此处转发
    }
 
    //function<>成员
    CURLCallback _callback;
};
 
int main()
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL* handle = curl_easy_init();
    string url = "ftp://d2school:123456@127.0.0.1/:21";
    curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
 
    //构造一个CURLFunctionHelper对象,指明配置项和HEADER相关,在构造函数中,完成handle的设置
    CURLFunctionHelper helper(handle, CURLOPT_HEADERFUNCTION, CURLOPT_HEADERDATA);
 
    //绑定一个lambda表达式,注意它的入参和返回值
    helper.Bind([](char* data, size_t size, size_t nmemb)->size_t
            {
                std::string line(data, size*nmemb);
                cout << line;
                return size*nmemb;
            });
 
    curl_easy_perform(handle);
    curl_easy_cleanup(handle);
    curl_global_cleanup();
    return 0;
}

50行,声明一个helper对象,该对象的构造函数中,完成了回调函数的设置

          其中,13行,将静态成员函数inner_function设置为回调函数,而inner_function中需要访问非静态成员_call_back, 这需要一个CURLFunctionHelper对象,所以14行,将this对象传递给了inner_function。

53行,调用helper的Bind() 成员函数,Bind()函数,通过转移的方式,将Lambda表达式

[](char* data, size_t size, size_t nmemb)->size_t
            {
                std::string line(data, size*nmemb);
                cout << line;
                return size*nmemb;
            }

赋给了_callback成员。

实际执行过程,将执行30行的静态成员函数inner_function,而inner_function中,self是14行传递过来的this,35行,调用_callback, 而_callback就是Bind函数转移过来的Lambda表达式,从而实现了对ftp报头数据的打印。

运行效果如下图:

绑定函数对象
#include <curl/curl.h>
#include <iostream>
#include <fstream>
#include <string>
#include <functional>

using namespace std;

struct CURLFunctionHelper
{
    CURLFunctionHelper(CURL* curl, CURLoption opt_function, CURLoption opt_data)
    {
        curl_easy_setopt(curl, opt_function, inner_function);
        curl_easy_setopt(curl, opt_data, this);
    }

    template <typename Fn>

    void Bind(Fn&& fn) //参数类型为右值
    {
        _callback = std::move(fn);//转移
    }

private:
    //简化function类型表达
    typedef std::function <size_t(char*, size_t, size_t)> CURLCallback;
    //负责转接的静态成员函数
    static size_t inner_function(char* data
                                 , size_t size, size_t nmemb
                                 , void* userdata)
    {
        auto self = static_cast <CURLFunctionHelper*> (userdata);
        return self->_callback(data, size, nmemb); //在此处转发
    }

    //function<>成员
    CURLCallback _callback;
};

struct StdOutputer
{
    size_t operator()(char* data, size_t size, size_t nmemb)
    {
        std::string line(data, size*nmemb);
        cout << line ;
        return size*nmemb;
    }
};

int main()
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL* handle = curl_easy_init();
    string url = "ftp://d2school:123456@127.0.0.1/:21";
    curl_easy_setopt(handle, CURLOPT_URL, url.c_str());

    CURLFunctionHelper helper(handle, CURLOPT_HEADERFUNCTION, CURLOPT_HEADERDATA);

    //绑定一个函数对象,注意它的入参和返回值
    StdOutputer outputer;
    helper.Bind(outputer);

    curl_easy_perform(handle);
    curl_easy_cleanup(handle);
    curl_global_cleanup();
    return 0;
}
绑定非静态成员函数
#include <curl/curl.h>
#include <iostream>
#include <fstream>
#include <string>
#include <functional>
 
using namespace std;
 
struct CURLFunctionHelper
{
    CURLFunctionHelper(CURL* curl
                       , CURLoption opt_function, CURLoption opt_data)
    {
        curl_easy_setopt(curl, opt_function, inner_function);
        curl_easy_setopt(curl, opt_data, this);
    }
 
    template <typename Fn>
    void Bind(Fn&& fn)
    {
        _callback = std::move(fn);
    }
 
    template <typename Fn, typename C>
    void BindMember(Fn&& fn, C* c)
    {
        _callback = MakeMemberCallBack(fn, c);
    }
 
private:
    typedef std::function <size_t(char* , size_t, size_t)> CURLCallback;
 
    template <typename Fn, typename C>
    CURLCallback MakeMemberCallBack(Fn&& fn, C* c)
    {
        return std::bind(C::on_write, c, std::placeholders::_1
                                       , std::placeholders::_2
                                       , std::placeholders::_3);
    }
 
    static size_t inner_function(char* data, size_t size
                                 , size_t nmemb, void* userdata)
    {
        auto self = static_cast <CURLFunctionHelper*> (userdata);
        return self->_callback(data, size, nmemb);
    }
 
    CURLCallback _callback;
};
 
struct StdOutputer
{
    size_t on_write(char* data, size_t size, size_t nmemb)
    {
        std::string line(data, size*nmemb);
        cout << line;
        return size*nmemb;
    }
};
 
int main()
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL* handle = curl_easy_init();
    string url = "ftp://d2school:123456@127.0.0.1/:21";
    curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
 
    CURLFunctionHelper helper(handle, CURLOPT_HEADERFUNCTION, CURLOPT_HEADERDATA);
 
    //绑定一个函数对象,注意它的入参和返回值
    StdOutputer outputer;
    helper.Bind(std::bind(StdOutputer::on_write
                          , &outputer//this指针
                          , std::placeholders::_1, std::placeholders::_2
                          , std::placeholders::_3));
 
    curl_easy_perform(handle);
    curl_easy_cleanup(handle);
    curl_global_cleanup();
 
    return 0;
}

  • 25
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习中最常用的数学工具是线性代数、微积分和概率论。下面是一些基本的数学概念和 Python 代码示例: 1. 向量和矩阵 向量是一列数字,矩阵是一个二维数组。在 Python 中,可以使用 NumPy 库来创建和操作向量和矩阵。 ```python import numpy as np # 创建向量 v = np.array([1, 2, 3]) # 创建矩阵 m = np.array([[1, 2], [3, 4], [5, 6]]) # 矩阵乘法 result = np.dot(m, v) print(result) ``` 2. 梯度下降 梯度下降是一种优化算法,用于最小化损失函数。在 Python 中,可以使用 NumPy 和 SciPy 库来实现梯度下降算法。 ```python import numpy as np from scipy.optimize import minimize # 定义损失函数 def loss_function(w, X, y): y_hat = np.dot(X, w) return np.mean((y_hat - y) ** 2) # 定义梯度函数 def gradient(w, X, y): y_hat = np.dot(X, w) return np.dot(X.T, y_hat - y) / len(y) # 使用梯度下降算法求解 X = np.array([[1, 2], [3, 4], [5, 6]]) y = np.array([1, 2, 3]) w0 = np.zeros(X.shape[1]) res = minimize(loss_function, w0, args=(X, y), jac=gradient) print(res.x) ``` 3. 偏导数和梯度 偏导数是多元函数中某个变量的导数,梯度是多元函数的导数向量。在 Python 中,可以使用 SymPy 库来计算偏导数和梯度。 ```python from sympy import symbols, diff # 定义符号变量和函数 x, y = symbols('x y') f = x ** 2 + y ** 3 # 计算偏导数 df_dx = diff(f, x) df_dy = diff(f, y) print(df_dx, df_dy) # 计算梯度 grad = [diff(f, var) for var in [x, y]] print(grad) ``` 4. 概率分布和随机变量 概率分布是随机变量可能取值的概率分布。在 Python 中,可以使用 SciPy 库来计算概率分布和随机变量。 ```python from scipy.stats import norm # 定义正态分布 mu, sigma = 0, 1 dist = norm(mu, sigma) # 计算概率密度函数和累积分布函数 x = np.linspace(-3, 3, 1000) pdf = dist.pdf(x) cdf = dist.cdf(x) # 生成随机变量 samples = dist.rvs(1000) ``` 以上是一些基本的数学概念和 Python 代码示例。在机器学习中,还会涉及到更高级的数学工具,如矩阵分解、优化理论、贝叶斯统计等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值