1. 程式人生 > >boost庫使用總結

boost庫使用總結

1VC6min/max的災難

當在VC中使用boost庫,或者其他庫的時候會有一些小的問題。

Windows的標頭檔案中已經定義了min max巨集,所以在STL中的這兩個函式就呼叫不到了,例如在MFC中就是這樣,但是在Boost中,都是使用的std::名稱空間下的函式,使用Windows的函式不能夠接受不同型別的引數在模板中使用,但是許多庫都依賴這些。

雖然Boost儘量處理這些問題,但有時候遇到這樣的問題的時候就需要在自己的程式碼中加入像下面的程式碼在第一個#include前加入#define _NOMINMAX

#define _NOMINMAX            // disable windows.h defining min and max as macros

#include "boost/config.hpp"  // include boosts compiler-specific "fixes"

using std::min;              // makle them globally available

using std::max;

這樣操作並不是在任何時候都需要,而只有我們碰到使用了就需要加入這段程式碼。

2字串查詢函式效能

字串查詢的時候,boost庫提供了一個boost::containsboost::icontains方法,後者忽略字串大小寫。但是在測試效能的時候,這兩個函式對效能影響巨大,使用string/wstring自帶的find

函式,效能會提高不少。boost::icontain耗效能的主要原因查看了原始碼,發現主要是在內部做了多次is_equal()的呼叫,且每次is_equal時都會進行to_upper()或者to_lower()一類的操作。所以非常考慮效能的話建議使用string自帶的find

resolver的非同步查詢(async_resolve)讓我搞了1個小時,雖然教程上說根據說明文件很容易使用async_resolve,但是實際編寫時就遇到問題了。
bug:非同步完成控制代碼被呼叫時始終傳入error
但從網上查資料,基本跟我寫的一樣啊,沒什麼區別。最後各種嘗試,終於找出裡面的原因來了。
解決方法:io_service

必須要在socket,resolver初始化之後才能呼叫run()函式,否則非同步查詢始終出錯。

3any這個類提供了像shared_ptr一樣的功能:能夠包含任意型別。但是any不是一個模板類。所以我們可以在stl的容器中使用其作為型別引數,這樣我們就可以實現在stl容器中包含任意型別的目的了。any中的any_cast是其精髓,想要訪問any中的例項都需要這個介面去獲得新的例項拷貝。

4operator
operators
標頭檔案中包含了很多有便擴充套件操作符過載的解決方案,就像書中寫的,如果我們提供operator<,那麼我麼應該提供operator<=,>=,>等操作符,但是其實我們發現,通過opertor<我們能夠推出operator<=,operator>=,operator>等操作符,但是我們卻往往忽略,或者怕出錯誤,以至於我們類的操作符過載不夠友好,使用者使用不能像預想的那樣。opertors庫,讓這些依賴於主操作符過載的輔操作符過載更簡單,而且更加概念化,系統化。通過派生於less_than_comparable<typename T>,我們就能實現比較,通過其他概念,我們將更加簡單而且清晰的實現各類應該具備的操作符。

5、解決boost包含boost/algorithm/string.hpp造成的__int64錯誤

使用booststring庫進行跨平臺操作,包含檔案

#include <boost/algorithm/string.hpp>

結果遇到編譯錯誤

error C2632: '__int64' followed by '__int64' is illegal

發現在config-win32.h已經定義過巨集,boost\cstdint.hpp又使用了一次typedef,解決方法,增加解決方法,增加#undefint64_t

#undef int64_t

#include <boost/algorithm/string.hpp>

6、解決boost包含#include<boost/asio/ip/tcp.hpp>造成的“error C2632:“__int64”後面的“__int64”非法錯誤

解決方法,增加#undefint64_t

#undefint64_t

#include<boost/asio/ip/tcp.hpp>

#include<boost/asio.hpp>

#include<boost/bind.hpp>

#include<boost/enable_shared_from_this.hpp>

#include<boost/shared_ptr.hpp>

#include<boost/array.hpp>

#include<boost/function.hpp>

7、使用智慧指標的幾個注意點

智慧指標是一種像指標的C++物件,但它能夠在物件不使用的時候自己銷燬掉。

我們知道在C++中的物件不再使用是很難定義的,因此C++中的資源管理是很複雜的。各種智慧指標能夠操作不同的情況。當然,智慧指標能夠在任務結束的時候刪除物件,除了在程式之外。

許多庫都提供了智慧指標的操作,但都有自己的優點和缺點。Boost庫是一個高質量的開源的C++模板庫,很多人都考慮將其加入下一個C++標準庫的版本中。

boost定義智慧指標種類。

shared_ptr<T>

內部維護一個引用計數器來判斷此指標是不是需要被釋放。是boost中最常用的智慧指標了。

scoped_ptr<t>

當這個指標的作用域消失之後自動釋放

intrusive_ptr<T>

也維護一個引用計數器,比shared_ptr有更好的效能。但是要求T自己提供這個計數器。

weak_ptr<T>

弱指標,要和shared_ptr結合使用

shared_array<T>

shared_ptr相似,但是訪問的是陣列

scoped_array<T>

scoped_ptr相似,但是訪問的是陣列

下面是幾個使用智慧指標需要注意的地方:

宣告一個智慧指標的時候要立即給它例項化, 而且一定不能手動釋放它。

…_ptr<T>不是T*型別。所以:

               a: 宣告的時候要…_ptr<T>而不是….._ptr<T*>

               b:不能把T*型的指標賦值給它

               c: 不能寫ptr=NULl,而用ptr.reset()代替。

不能迴圈引用。

不要宣告臨時的share_ptr, 然後把這個指標傳遞給一個函式

// shared_ptr<T>用法例項

#include <stdio.h>
#include <boost/shared_ptr.hpp>
 
class A {
public:
    void print() {
       printf("class A print!\n");
    }
};
 
int main(int argc, char **argv) {
   boost::shared_ptr<A> a1(new A());
    a1->print();
}

8、獲取物件地址

&作為取址符號用來獲取物件的地址,但由於c++太靈活,通過過載operator&可以改變operator&原有的語意。當你需要使用物件的真實地址時,這種情況下boost庫中addressof函式。

#include"stdafx.h"
#include<iostream>
#include<boost/utility.hpp>
usingnamespaceboost;
usingnamespacestd;
 
classObject
{
public:
    Object(){m_age = 22;}
    intoperator&()
    {
        return0;
    }
    intGetAge(){returnm_age;}
 
protected:
    intm_age;
};
 
intmain()
{
    Objectobj;
    cout<<&obj<<endl;//輸出
    Object *p=addressof(obj);
    cout<<p<<endl;//輸出obj真實地址
    cout<<p->GetAge()<<endl;
}

9boost::asio async_write也不能保證一次發完所有資料

看過basic_stream_socket的文件,裡面提到async_write_some不能保證將所有要傳送的資料都發出去。並且提到如果想這樣做,需要使用boost asioasync_write

async_write有時也無法一次發完資料。因此只好自己寫了一個重試傳送的遞迴函式。也很簡單,通過bind,每次傳遞想要傳送的位元組數木和傳送開始位置給非同步回撥函式。

程式碼參考如下:

void Sign::AfterWriteMessage(error_code const& ec,size_t bytes_transferred, size_t expected_size, size_t offset) {
  if (ec) {
   BOOSTER_ERROR("AfterWriteMessage") << "writemessage failed, error code:" << ec.value()
                       << " category name:"<< ec.category().name()
                       << " id_:" << id_
                       << " address:" <<address  
                       << " message:" <<ec.message();
    Close();
    return;
  }
 
 BOOSTER_DEBUG("AfterWriteMessage") << "thread id:" << this_thread::get_id() << " send_buffer: "<< PrintBytesAsHexString(send_buffer, bytes_transferred) << "sent size:" << bytes_transferred;
 BOOSTER_DEBUG("AfterWriteMessage") << "thread id:" << this_thread::get_id() << " send_buffer: "<< PrintBytesAsHexString(send_buffer, expected_size) << "expected size:" << expected_size;
  
  size_tresend_size = expected_size - bytes_transferred;
  if (resend_size> 0) {
    size_tnew_offset = offset + bytes_transferred;
   async_write(socket, buffer((void*)&send_buffer[new_offset],resend_size),
        strand_.wrap(bind(&Sign::AfterWriteMessage,shared_from_this(), _1, _2, resend_size, new_offset)));
    return;
  }
 
  // do yourbusiness after send succeeds
  
}
 
void Sign::SendMessage(size_t size) {
  //  BOOSTER_DEBUG("SendMessage")<< "thread id: " << this_thread::get_id() << "send_buffer: " << PrintBytesAsHexString(send_buffer, size) <<" size:" << size;
 async_write(socket, buffer(send_buffer, size),
          strand_.wrap(bind(&Sign::AfterWriteMessage,shared_from_this(), _1, _2, size, 0)));
}

10、使用enable_shared_from_this

繼承該類就可以進行基於當前子類進行安全的weap_ptrshared_ptr的轉換...
程式碼例項
以下程式碼中Y類繼承enable_shared_from_this,,從而我們可以直接在函式中呼叫shared_from_this獲得該物件的shared_ptr

class Y: publicenable_shared_from_this<Y>
{
public:

    shared_ptr<Y> f()
    {
        returnshared_from_this();
    }
}

int main()
{
    shared_ptr<Y> p(newY);
// 呼叫f獲得shared_ptr

    shared_ptr<Y> q =p->f();
    assert(p == q);
    assert(!(p < q || q <p)); // p and q must share ownership

}

11boost

boost讀寫鎖,共享-獨佔鎖,當讀寫鎖以讀模式鎖住時,它是以共享模式鎖住的,當它以寫模式鎖住時,它是以獨佔模式鎖住的。

typedefboost::shared_lock<boost::shared_mutex> readLock;

typedef boost::unique_lock<boost::shared_mutex> writeLock;

boost::shared_mutex rwmutex;

void readOnly( )

{

readLock rdlock(rwmutex);

// do something

}

void writeOnly( )

{

writeLock wtlock(rwmutex);

// do something

}

對同一個rwmutex,執行緒可以同時有多個readLock,這些readLock會阻塞任意一個企圖獲得writeLock的執行緒,直到所有的readLock物件都析構。如果writeLock首先獲得了rwmutex,那麼它會阻塞任意一個企圖在rwmutex上獲得readLock或者writeLock的執行緒。

互斥鎖

typedef boost::unique_lock<boost::mutex> exclusiveLock;

遞迴式的互斥量

boost::recursive_mutex提供一個遞迴式的互斥量。對於一個例項最多允許一個執行緒擁有其鎖定,如果一個執行緒已經鎖定一個boost::recursive_mutex例項,那麼這個執行緒可以多次鎖定這個例項。

12boost::asioasync_readasync_read_some的區別

asio::async_read通常使用者讀取指定長度的資料,讀完或出錯才返回。 而socketasync_read_some讀取到資料或出錯就返回,不一定讀完了整個包!

void async_read(AsyncReadStream& s, constMutableBufferSequence& buffers,ReadHandler handler)時,必須等到填滿Buffer,否則即使收到資料包,也不會沒有呼叫ReadHandler控制代碼。

boost::asio::async_read(m_socket,boost::asio::buffer(recvData,nNeedRecvLen),
boost::bind(&ClientSession::handle_read,this,boost::asio::placeholders::error));

boost::array<char,512>m_recvBuf;

ip::tcp::socket m_socket;

//同步

boost::system::error_codeerror;
std::size_tnSize = m_socket.read_some(boost::asio::buffer(m_recvBuf),error);
//非同步
m_socket.async_read_some(boost::asio::buffer(m_recvBuf),
            boost::bind(&TcpConnection::handle_read, this,
            boost::asio::placeholders::error, 
            boost::asio::placeholders::bytes_transferred));

sync_read_some函式一次只能接收大約1k資料,如果要接收大資料,需要反覆接收。

13boost庫各個版本下載地址

Boost庫各個版本下載地址: