青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

那誰(shuí)的技術(shù)博客

感興趣領(lǐng)域:高性能服務(wù)器編程,存儲(chǔ),算法,Linux內(nèi)核
隨筆 - 210, 文章 - 0, 評(píng)論 - 1183, 引用 - 0
數(shù)據(jù)加載中……

C++的流設(shè)計(jì)很糟糕

最近需要提供一個(gè)功能,采用類(lèi)似C++流輸出的格式輸出一些日志信息, 例如Log(FATAL) << "log to" .

我找了兩個(gè)類(lèi)似項(xiàng)目來(lái)研究,google的gloglog4cpp, 它們都支持以C++流輸出格式進(jìn)行輸出.

但是研究到最后,我發(fā)現(xiàn)最大的問(wèn)題是, 如果按照C++的流輸出格式進(jìn)行輸出, 將無(wú)法判定需要輸出的信息到哪里是結(jié)束.比如log << "hello " << "world",是無(wú)法判斷到底在輸出"hello"還是"world"的時(shí)候上面的參數(shù)輸入已經(jīng)結(jié)束了.上面兩個(gè)項(xiàng)目中, 解決這個(gè)問(wèn)題的辦法大致是相同的,以下面可編譯運(yùn)行代碼為例說(shuō)明它們的做法(在linux g++下面編譯通過(guò)):
#include <iostream>
#include 
<sstream>

#ifdef __DEPRECATED
// Make GCC quiet.
 # undef __DEPRECATED
 # include 
<strstream>
 # define __DEPRECATED
#else
 # include 
<strstream>
#endif

using namespace std;

class LoggerStream : public std::ostrstream {
 
public:
  LoggerStream(
char * buf, int len)
   : ostrstream(buf, len),
    buf_(buf),
    len_(len) {
  }

  
~LoggerStream() {
    
// do the real fucking output
    cout << buf_;
  }

 
private:
  
char *buf_;
  
int len_;
};

int main() {
  
char buf[100= {'\0'};

  LoggerStream(buf, 
sizeof(buf)) << 1 << " hello world\n";

  cout 
<< "buf = " << buf << endl;

  
return 0;
}

在上面的代碼中, 開(kāi)始進(jìn)行輸出的時(shí)候首先初始化一個(gè)LoggerStream對(duì)象, 而在輸出參數(shù)輸入完畢的時(shí)候?qū)⒄{(diào)用它的析構(gòu)函數(shù),在這個(gè)析構(gòu)函數(shù)中才完成真正的輸出動(dòng)作.也就是說(shuō),由于對(duì)輸入?yún)?shù)結(jié)束位置判斷手段的缺失,C++中不得不采用這個(gè)手段在析構(gòu)函數(shù)中完成最終的輸出工作.
這樣的做法,最大的問(wèn)題是,頻繁的構(gòu)造/析構(gòu)開(kāi)銷(xiāo)大,而且每個(gè)"<<"操作符背后又需要調(diào)用ostream的operator<<,也就是假如你的輸入?yún)?shù)有三個(gè)將調(diào)用operator <<三次(當(dāng)然是經(jīng)過(guò)重載的,不一定都是同一個(gè)operator<<),因此,假如需要考慮多線(xiàn)程的話(huà),那么一次輸入有多個(gè)函數(shù)函數(shù)中被調(diào)用,仍然是問(wèn)題.天,要使用這門(mén)語(yǔ)言寫(xiě)出正確的程序來(lái),需要了解底下多少的細(xì)節(jié)呢?!

最后,我向項(xiàng)目組反映這個(gè)問(wèn)題,一致同意以C中類(lèi)似sprintf可變參數(shù)的形式實(shí)現(xiàn)這個(gè)功能.可變參數(shù)解決這個(gè)問(wèn)題,就我的感覺(jué)而言,就是輸入?yún)?shù)的時(shí)候,稍顯復(fù)雜,需要用戶(hù)指定輸入的格式.然而,其實(shí)這個(gè)做法也有好處:作為函數(shù)的使用者,你必須明確的知道你在做什么并且反饋給你所使用的函數(shù).明確的,無(wú)歧義的使用函數(shù),而不是依靠所謂函數(shù)重載猜你的用意,我想也是避免問(wèn)題的一個(gè)手段.gcc中, 提供了對(duì)可變參數(shù)檢查的機(jī)制,見(jiàn)這里.

posted on 2010-07-06 13:04 那誰(shuí) 閱讀(14894) 評(píng)論(79)  編輯 收藏 引用 所屬分類(lèi): C\C++

評(píng)論

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

你為什么要了解細(xì)節(jié)呢,你只需要知道無(wú)論什么類(lèi)型只要編譯通過(guò)都能operator<<就行了。而且結(jié)束很好判斷,自己寫(xiě)一個(gè)全局變量:

class MyEndLine
{
} myEndLine;

重載operator<<(MyStream&, const MyEndLine&)

最后
myStream<<1<<2<<3<<MyEndLine。

解決。

可變參數(shù)什么的,沒(méi)有討論的余地,新代碼絕對(duì)不能用。除非你確信你、你的同事或者你的手下的水平都高超到用可變參數(shù)而絕對(duì)不會(huì)產(chǎn)生內(nèi)存問(wèn)題譬如說(shuō)溢出啊之類(lèi)。
2010-07-06 13:52 | 陳梓瀚(vczh)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

樓主,批C++可以,但你為什么要這樣批呢?

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

使用C++類(lèi)庫(kù)的大忌之一:通過(guò)閱讀代碼而不是寫(xiě)測(cè)試來(lái)了解功能
使用C++類(lèi)庫(kù)的大忌之二:如果有文檔/demo,也非得通過(guò)閱讀代碼而不是寫(xiě)測(cè)試來(lái)了解功能
使用C++類(lèi)庫(kù)的大忌之三:通過(guò)閱讀代碼而不是寫(xiě)測(cè)試來(lái)獲得性能上的數(shù)據(jù)

總之:非必要情況下,如果你非得了解代碼才能知道一個(gè)類(lèi)庫(kù)怎么用,而且如果類(lèi)庫(kù)的文檔/demo還很好的話(huà),那絕對(duì)是你自己的問(wèn)題。

一般來(lái)說(shuō),質(zhì)量好的C++的類(lèi)庫(kù)都做到,編譯通過(guò)了一般都不會(huì)有【大】問(wèn)題,就算有了問(wèn)題也會(huì)被assert出來(lái)的。
2010-07-06 13:54 | 陳梓瀚(vczh)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳梓瀚(vczh)
嗯,你說(shuō)的那種方式 確實(shí)也是個(gè)辦法吧.
2010-07-06 13:55 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
所以為了項(xiàng)目的安全,我還是建議你不要使用可變參數(shù)
2010-07-06 13:56 | 陳梓瀚(vczh)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳梓瀚(vczh)
C++的設(shè)計(jì)里面 編譯器做了太多額外的事情 以至于你要用好這么語(yǔ)言不得不去多了解細(xì)節(jié) 我覺(jué)得這是很糟糕的地方 因?yàn)槟阈枰冻龊艽蟮拇鷥r(jià)才能對(duì)這門(mén)語(yǔ)言有足夠的了解.
2010-07-06 14:03 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳梓瀚(vczh)
我想了想 你這樣還是有問(wèn)題的,比如一次輸入幾個(gè)參數(shù) 將會(huì)在幾次函數(shù)調(diào)用中完成 如果我需要做到是多線(xiàn)程的 這一點(diǎn)如何保證呢?還是類(lèi)sprintf那樣的在一個(gè)函數(shù)中搞定所有的事情吧.
2010-07-06 14:11 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

鮮明的對(duì)比:

學(xué)會(huì)了errno就學(xué)不會(huì)exception。
學(xué)會(huì)了prints就學(xué)不會(huì)streams。
學(xué)會(huì)了C就學(xué)不會(huì)C++。
。。。

學(xué)會(huì)了errno繼續(xù)學(xué)exception。
學(xué)會(huì)了printfs繼續(xù)學(xué)streams。
學(xué)會(huì)了C繼續(xù)學(xué)C++。
。。。
2010-07-06 14:16 | OwnWaterloo

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

#define LOG_PUTS(log, record) \
do{ \
std::ostringstream os; \
os << record; \
lg->puts(os.str().c_str(), os.str().length()); \
}while(0)


這樣不就行了嗎
2010-07-06 14:22 | cui

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

既然是寫(xiě)log,你不會(huì)想要調(diào)用一次operator <<就真的寫(xiě)一次設(shè)備吧?那可是IO速度差著幾個(gè)數(shù)量級(jí)的設(shè)備呢(C++的標(biāo)準(zhǔn)庫(kù)也是用了buffer,不信你可以去測(cè))

否則這樣的操作效率何在?xxx << 1 << 2 << 3 << 4 << 5 << 6 << 7;

熟悉C的話(huà),可以這樣理解:一次<<其實(shí)就是添加一個(gè)sprintf中的參數(shù)

建議在碰到endl再真的向物理設(shè)備輸出。這樣的話(huà)thread safe很容易做到——如果不這樣的話(huà),多線(xiàn)程一起輸出log,即使thread safe了,log也沒(méi)法看了

# re: C++的流設(shè)計(jì)很糟糕[未登錄](méi)  回復(fù)  更多評(píng)論   

兄弟, 你走遠(yuǎn)了吧. log4cpp的流使用方式就很好啊,類(lèi)似如此:

#define SLOG(Level,Event) \
do{ \
std::ostringstream _SLOG_BUF_INTERNAL_; \
_SLOG_BUF_INTERNAL_<<Event; \
printf_log(Level,_SLOG_BUF_INTERNAL_.str().c_str()); \
}while(0)
2010-07-06 14:28 | cppexplore

# re: C++的流設(shè)計(jì)很糟糕[未登錄](méi)  回復(fù)  更多評(píng)論   

@cui
......................驚人的一致............
2010-07-06 14:29 | cppexplore

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

我寫(xiě)過(guò)一個(gè)小的日志庫(kù),已經(jīng)在產(chǎn)品中使用過(guò),
http://code.google.com/p/cute-log/
2010-07-06 14:55 | cui

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

最大的問(wèn)題是,頻繁的構(gòu)造/析構(gòu)開(kāi)銷(xiāo)大
這個(gè)應(yīng)該可以通過(guò)單例模式解決吧
你這篇文章是不是主要想說(shuō)明輸出多個(gè)參數(shù)的時(shí)候會(huì)多次調(diào)用“<<”,
而使用“sprintf”效率會(huì)比較高,是這樣么?
2010-07-06 15:00 | joewan

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

是LoggerStream寫(xiě)得有問(wèn)題,如果你要這樣寫(xiě),可以考慮寫(xiě)一個(gè)類(lèi)似endl的操作子來(lái)做真正的輸出
2010-07-06 16:25 | t

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

記得上次看你一篇博文,google的c++編程規(guī)范里面規(guī)定了不準(zhǔn)使用c++的流,全部用printf一族。對(duì)于蹩腳的東西干脆不用,很好。
2010-07-06 17:03 | 趙建寅

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

linux kernel,apache,lighttpd,nginx,mysql,postgresql都是純C寫(xiě)的(mysql中有少量C++代碼,在非核心的部分)。C++程序員應(yīng)該反思。C++的某些語(yǔ)言特性在誘導(dǎo)程序員作出不合理的設(shè)計(jì)。。。KISS是王道。
2010-07-06 21:00 | c-programmer

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳梓瀚(vczh)
另外,還有個(gè)問(wèn)題,很難在編譯語(yǔ)法層面保證你的最后一個(gè)輸入是那個(gè)標(biāo)記類(lèi)吧....
2010-07-06 22:26 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

to cui and cppexplore
我們看的不是一個(gè)地方,呵呵.
2010-07-06 22:35 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

C++ 流其實(shí)就是一個(gè)文件流,其實(shí)當(dāng)初設(shè)計(jì)C++ 的人,大多數(shù)是混口飯吃的,當(dāng)然,他們的責(zé)任心是有的,但是責(zé)任心跟專(zhuān)心是有區(qū)別的,愛(ài)好者很多時(shí)候,比專(zhuān)業(yè)人士對(duì)于該專(zhuān)業(yè)更加用心。
2010-07-06 22:43 | 飛鴿傳書(shū)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

能用C方式解決的就用C,該用STL的就用STL。
我覺(jué)得如何發(fā)現(xiàn)蹩腳,那就是選擇的不對(duì)。或者是使用的不對(duì)。
2010-07-06 22:52 | xx

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳梓瀚(vczh)
為什么說(shuō)是大忌呢?
2010-07-07 02:40 | 夜風(fēng)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

C++比較適合描述數(shù)據(jù)關(guān)系
C比較適合描述流程
應(yīng)該結(jié)合起來(lái)用。

不沖突。


2010-07-07 03:46 | johndragon

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
多線(xiàn)程輸出IO信息是不對(duì)的,請(qǐng)修改設(shè)計(jì)。
2010-07-07 11:14 | 陳梓瀚(vczh)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
C++難學(xué)是難學(xué),你見(jiàn)過(guò)有人抱怨過(guò)微積分太難學(xué)而說(shuō)幾何比微積分好的嗎(初級(jí)的微積分解決的問(wèn)題跟幾何是一樣的)
2010-07-07 11:15 | 陳梓瀚(vczh)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
實(shí)在不行,你可以
Write(StringBuidler<<"vczh"<<" is "<<" a "<<" programmer!");總行了吧。雖然長(zhǎng)了一點(diǎn),也總比printf好。之余語(yǔ)法怎么調(diào)整你自己去想就好了。
2010-07-07 11:18 | 陳梓瀚(vczh)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳梓瀚(vczh)
呵呵,不知道你有沒(méi)有寫(xiě)過(guò)服務(wù)器端程序,多線(xiàn)程同時(shí)寫(xiě)log是肯定會(huì)存在的.
至于說(shuō)的sprintf有緩沖區(qū)溢出問(wèn)題,也可以有做法進(jìn)行避免.
總之,我的結(jié)論是C++的流在判斷輸入結(jié)束方面存在缺陷,至于后面跟的帖子寫(xiě)的其他格式,則不是我關(guān)注的重點(diǎn)了,我這篇文章只為了說(shuō)明C++的這個(gè)缺陷,這是我寫(xiě)這篇文章的目的.

另外,你那個(gè)微積分和幾何的比喻放在這里不妥,兩者不能解決相同的問(wèn)題,不屬于一個(gè)類(lèi)型.
2010-07-07 11:24 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
我覺(jué)得不是需不需要多線(xiàn)程log的問(wèn)題,而是實(shí)際上在寫(xiě)的線(xiàn)程只能有一個(gè)。舉個(gè)例子,你有一個(gè)log線(xiàn)程,暴露一個(gè)隊(duì)列,其他線(xiàn)程往里面填,然后log線(xiàn)程去寫(xiě)文件。

C++難并不是缺陷,其實(shí)每一個(gè)細(xì)節(jié)都規(guī)定的十分清晰。而且C++那些也不是毫無(wú)規(guī)律的,C++試圖做到每一個(gè)語(yǔ)法你都可以去寫(xiě)callback,應(yīng)該好好理解這一點(diǎn)。
2010-07-07 11:44 | 陳梓瀚(vczh)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
變量創(chuàng)建銷(xiāo)毀有callback(構(gòu)造函數(shù)析構(gòu)函數(shù)),復(fù)制有callback,操作符有callback(可以重載),等等。當(dāng)然我認(rèn)為構(gòu)造函數(shù)和析構(gòu)函數(shù)是非常簡(jiǎn)單的,復(fù)雜的是overloading,一般來(lái)說(shuō)我很少使用。實(shí)際上最復(fù)雜的是模板,這個(gè)你不反對(duì)吧,而且我認(rèn)為你們也應(yīng)該不會(huì)使用模板,或者僅僅使用模板的低級(jí)形式。因此拋開(kāi)這些之后,我不知道你認(rèn)為還有什么地方是“復(fù)雜”的。如果你說(shuō)的是stl復(fù)雜,那顯然跟C++沒(méi)關(guān)系。
2010-07-07 11:46 | 陳梓瀚(vczh)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳梓瀚(vczh)
"其實(shí)每一個(gè)細(xì)節(jié)都規(guī)定的十分清晰"
我還真沒(méi)有覺(jué)得,也許是真的,但是要做到使用者也非常清晰,代價(jià)很大.就學(xué)一門(mén)語(yǔ)言的代價(jià)而言,我覺(jué)得過(guò)大,因?yàn)檎Z(yǔ)言不是全部,還有很多需要學(xué)的,如果過(guò)分多的把精力放在語(yǔ)言學(xué)習(xí)上,我覺(jué)得有點(diǎn)本末倒置.所以,我現(xiàn)在只使用那些我清楚的,有把握的C++特性,你可以說(shuō)我保守,但是我不是學(xué)生,沒(méi)多少時(shí)間花在語(yǔ)言學(xué)習(xí)上.
2010-07-07 11:47 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳梓瀚(vczh)
也有用模板,用模板創(chuàng)建callback,但是我不了解做法,只了解怎么使用,模板讓我很崩潰,一直不想深究.
2010-07-07 11:48 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
我開(kāi)了個(gè)新的首頁(yè)的文章,我們挪去那里好了,你可以把你認(rèn)為受不了的地方列出來(lái),然后我們討論討論。當(dāng)然最好說(shuō)的詳細(xì)一點(diǎn),這樣有助于雙方的理解。
2010-07-07 11:54 | 陳梓瀚(vczh)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

C++語(yǔ)言本身沒(méi)有任何問(wèn)題,是你掌握得不是很熟練。
C++作為語(yǔ)言,只是一種表達(dá)工具,而一個(gè)設(shè)計(jì)的好壞跟語(yǔ)言本身是沒(méi)有任何關(guān)系的,只要有思想,C++可以做出非常好的設(shè)計(jì)的。
之所以以懷疑流的使用,只是你還沒(méi)有理解流,還沒(méi)有了解如何學(xué)得更好。
別動(dòng)不動(dòng)就批C++,還沒(méi)有理解它怎么能知道它不好呢?
C++難是難,學(xué)起來(lái)非常困難,難是因?yàn)樗珡?qiáng)大,造自行車(chē)不難,學(xué)會(huì)騎自行車(chē)也不難,而造飛機(jī)與開(kāi)飛機(jī)就非常難,沒(méi)開(kāi)好飛機(jī)摔了,能說(shuō)飛機(jī)不好嗎?
2010-07-08 13:06 | Noock

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@Noock
那請(qǐng)您就事論事說(shuō)一說(shuō)怎么解決我提的問(wèn)題,謝謝.
2010-07-08 13:08 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

說(shuō)C++復(fù)雜,那是因?yàn)槟銢](méi)清楚如何使用她~

C++標(biāo)準(zhǔn)庫(kù)的IO是挺不錯(cuò)的架設(shè),其實(shí),你或許不應(yīng)該從ostrstream繼承,應(yīng)該從basic_ostream,然后設(shè)計(jì)自己的basic_streambuf ,相當(dāng)簡(jiǎn)單實(shí)用
2010-07-08 18:04 | 陳煜

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳煜
那請(qǐng)您給出可運(yùn)行的代碼例子并且解決我上面的問(wèn)題,謝謝.


2010-07-08 18:11 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

請(qǐng)看
http://www.drdobbs.com/184401470;jsessionid=3I5YVJBUOELIJQE1GHPSKHWATMY32JVN?pgno=1

還有
http://www.codeproject.com/KB/debug/debugout.aspx
2010-07-08 21:39 | 陳煜

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳煜
呵呵,我把那個(gè)codeproject的代碼拉下來(lái)編譯驗(yàn)證,正是我上面給出來(lái)的結(jié)論.麻煩你自己回頭看看那份代碼和我文章中的描述吧.
以那個(gè)項(xiàng)目的代碼為例,在類(lèi)basic_debugbuf的析構(gòu)中調(diào)用了sync,這個(gè)函數(shù)中再調(diào)用output_debug_string輸出字符.就是我文章中提到的情況:因?yàn)镃++的流輸出對(duì)輸入?yún)?shù)的結(jié)束位置無(wú)法判斷,只能在析構(gòu)函數(shù)中做真正的輸出.

另外那篇文章,太長(zhǎng)了,我不去看了.
2010-07-08 21:55 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

為啥不使用flush呢?
2010-07-08 22:01 | 陳煜

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳煜
行了,我證明了你說(shuō)的辦法不能解決我這里提的問(wèn)題.就這樣吧.
給他人下結(jié)論之前,麻煩你做過(guò)充分的驗(yàn)證,我在上面可是有給出可編譯運(yùn)行的程序的,謝謝.
2010-07-08 22:04 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@陳煜
另外,這個(gè)問(wèn)題跟flush沒(méi)有一毛錢(qián)的關(guān)系,你這么問(wèn)說(shuō)明你對(duì)我提出的問(wèn)題還是不了解,呵呵.
2010-07-08 22:36 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

#include <iostream>
#include <ostream>
#include <sstream>
#include <strstream>

using namespace std;

struct streamend { };

class LoggerStream : public stringstream //public std::ostrstream
{
public:
static streamend end;
~LoggerStream( ) { DoPrint(); }

private:
void DoPrint( void )
{
cout<<"------- DoPrint( ) ------------"<<endl; // 只是用來(lái)證明何時(shí)調(diào)用了這個(gè)東東
cout<<this->str(); // real string
this->str("");
}
private:
friend ostream& operator<<(ostream& os, const streamend& end);
};

streamend LoggerStream::end;

// 第二個(gè)參數(shù)只是用來(lái)支持結(jié)束符
ostream& operator<<(ostream& os, const streamend&)
{
#if 1 // 0或1兩種方法都可以
ostream* pos = &os;
LoggerStream* pls = dynamic_cast<LoggerStream*>(pos);
if( pls != NULL)
pls->DoPrint();
#else
if( typeid(os) == typeid(LoggerStream))
((LoggerStream*)(&os))->DoPrint();
#endif
return os;
}

int main()
{
LoggerStream lstream; // 你只需要構(gòu)造一次,也可以聲明為靜態(tài)的
lstream << 1 << " hello world\n"<<LoggerStream::end;
lstream <<"line 1"<<LoggerStream::end<<"\nline 2\n"<<LoggerStream::end;

stringstream ss;
ss<<"hello"<<LoggerStream::end; // 此處LoggerStream::end沒(méi)有任何影響
return 0;
}
2010-07-08 23:09 | Noock

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@Noock
你這個(gè)辦法上面已經(jīng)有人說(shuō)過(guò)了.請(qǐng)看我的回復(fù),謝謝.
2010-07-08 23:14 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

不解決你說(shuō)的問(wèn)題嗎?
2010-07-08 23:17 | Noock

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@Noock
請(qǐng)問(wèn)你如何從語(yǔ)法,編譯器的角度避免用戶(hù)沒(méi)有輸入最后那個(gè)end呢?
2010-07-08 23:19 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

我在上面已經(jīng)就這個(gè)方式進(jìn)行了回復(fù),恕我不再回復(fù).
再說(shuō)一句,給他人定性下結(jié)論之前,自己先看清楚問(wèn)題,和別人的回復(fù),同時(shí)自己去驗(yàn)證過(guò)可行性,謝謝.
2010-07-08 23:21 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
另外,還有個(gè)問(wèn)題,很難在編譯語(yǔ)法層面保證你的最后一個(gè)輸入是那個(gè)標(biāo)記類(lèi)吧....


這個(gè)你使用printf更容易出問(wèn)題,后面幾個(gè)參數(shù)在編譯時(shí)是檢測(cè)不出來(lái)的,運(yùn)行時(shí)會(huì)致命的。
而且使用printf %d 輸出long long都有可能致命

而且,你定義的變量日后修改類(lèi)弄,你容易沒(méi)的修改格式字符串,那樣你的程序會(huì)在不必要的寫(xiě)日志時(shí)崩潰,而且是不確定的崩潰,在不確定平臺(tái)崩潰,有的平臺(tái)會(huì)死,有些平臺(tái)卻沒(méi)事兒
2010-07-08 23:25 | Noock

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@Noock
sprintf可以使用編譯器的特性進(jìn)行檢查,gcc就可以做到.
2010-07-08 23:27 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
編譯器擴(kuò)展是犧牲了可移植性的,當(dāng)然你也可以通過(guò)寫(xiě)個(gè)宏去避免這個(gè)問(wèn)題


#define LOG( content ) lstream<<content<<LoggerStream::end
LOG( "str1"<<1<<"str"<<2);

這個(gè)能不能滿(mǎn)足你的要求呢?
2010-07-08 23:41 | Noock

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@Noock
行了,到此打住吧,我只想證明這個(gè)東西是確實(shí)有缺陷的.到此為止.
2010-07-08 23:41 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
至少現(xiàn)在C++通過(guò)自己的特性還是解決了你的問(wèn)題,運(yùn)算符只是個(gè)函數(shù)而已,如何去使用是程序員自己的事,C++委員會(huì)也不會(huì)接受為了一個(gè)函數(shù)調(diào)用去修改C++的特性的。這個(gè)與C++的流設(shè)計(jì)也沒(méi)有什么關(guān)系,你上來(lái)就一個(gè)大標(biāo)題,

“C++的流設(shè)計(jì)很糟糕”

是不是有點(diǎn)兒太不負(fù)責(zé)任了?
2010-07-08 23:47 | Noock

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@Noock
我上面已經(jīng)回復(fù)了,你那個(gè)辦法怎么叫解決?不是又引入了新的問(wèn)題么?
"請(qǐng)問(wèn)你如何從語(yǔ)法,編譯器的角度避免用戶(hù)沒(méi)有輸入最后那個(gè)end呢?"

你的另一種做法,不是解決,叫規(guī)避,謝謝.
2010-07-09 00:45 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

說(shuō)白了,你提供了這個(gè)機(jī)制,又不提供相應(yīng)的檢查機(jī)制,如何叫"解決"?
2010-07-09 00:47 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
別老想著讓編譯器解決,C++設(shè)計(jì)語(yǔ)言的指導(dǎo)思想之一就是能通過(guò)已有特性解決的問(wèn)題就不進(jìn)行語(yǔ)言特性擴(kuò)展,別一門(mén)心思地讓編譯器來(lái)解決
編譯器這么多,只要不列入C++標(biāo)準(zhǔn),所有的擴(kuò)展都是不可移植的
考慮問(wèn)題是不是可以換個(gè)角度呢?
2010-07-09 09:27 | Noock

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@Noock
"解決"問(wèn)題應(yīng)該是"自封閉"的,也就是不引入別的問(wèn)題.在這里我提出的類(lèi)sprintf的解決方式,帶來(lái)的格式輸入有誤,緩沖區(qū)溢出等問(wèn)題,我都有方法解決掉,這才叫"解決"問(wèn)題.
你的第一種方式,帶來(lái)的另外一個(gè)問(wèn)題,你沒(méi)有幫我"解決"掉,所以,你這不叫"解決"問(wèn)題.
斗膽說(shuō)一句,平時(shí)工作中,你都是這么給人"解決"問(wèn)題的么?假設(shè)你是制造車(chē)的,我要解決代步問(wèn)題,從你那里買(mǎi)輛車(chē),如果還要擔(dān)心剎車(chē)會(huì)失靈,這個(gè)能叫做"解決"問(wèn)題么?

你的另一種方式,不是"解決"問(wèn)題,相反,恰恰如我說(shuō)的那樣,是這種方式存在缺陷,你才要使用別的方式規(guī)避它,這也就反證了這個(gè)方式是存在缺陷的了.

你說(shuō)到編譯器不能解決所有的問(wèn)題,我承認(rèn),但是要最大限度讓編譯器發(fā)揮作用來(lái)幫助解決問(wèn)題,人的因素很不穩(wěn)定,不能把項(xiàng)目的成敗過(guò)多的放在這些不穩(wěn)定因素中.

2010-07-09 10:34 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

對(duì)C++流的抱怨也不是一天兩天了,老是使用C的sprintf也不能算好的辦法,最好能使用類(lèi)型安全的printf,boost::format是一種解決辦法,還有一個(gè)fastformat也可以看一看,但是完美的設(shè)計(jì)是不存在的,還是看自己的需求吧。
2010-07-09 11:18 | wuqq

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
軟件最基本要求是正確,請(qǐng)教如果使用printf下面這個(gè)問(wèn)題如何解決?
char cc = -1;
printf("cc=%u\n", cc);
gcc 4.3.4 :
cc=4294967295

g++ -Wall 沒(méi)有任何警告
2010-07-09 13:38 | Noock

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@Noock
請(qǐng)看這里:
http://blog.chinaunix.net/u3/91522/showart_2054004.html
我的做法會(huì)在項(xiàng)目組內(nèi)禁止直接使用printf,而使用加上了__attribute__封裝的函數(shù).
緊跟著的問(wèn)題是,如何能保證禁止直接使用printf呢,define宏解決.
2010-07-09 13:47 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
1) gcc標(biāo)準(zhǔn)庫(kù)的printf也是加了__attribute__選項(xiàng)的,也能解決大部分的格式符,但上面我的那個(gè)例子是不行的,
你可以試一下你自己寫(xiě)的函數(shù)

你也可以把你的函數(shù)帖出來(lái),我?guī)湍泸?yàn)證一下。

2)既然你使用自己封裝的函數(shù)來(lái)打印,跟我原來(lái)定義一個(gè)宏LOG( )當(dāng)函數(shù)用來(lái)比有什么優(yōu)勢(shì)。
2010-07-09 15:14 | Noock

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@Noock
是的,我測(cè)試了一下,確實(shí)不行.查了一些文檔,發(fā)現(xiàn)是因?yàn)镃語(yǔ)言里面認(rèn)為,以%u輸出char是正確的,比如這里:
http://blog.csdn.net/wangyadong/archive/2009/05/22/4208013.aspx

我把代碼貼在這里:

#include <stdarg.h>

extern void my_printf(const char *format,...) __attribute__((format(printf,1,2)));

#define printf my_printf

int main() {
char cc = -1;
printf("cc=%u\n", cc);

return 0;
}

void my_printf(const char *format,...) {
// do the really fuck output
}

使用宏替代掉系統(tǒng)的printf的作用是,用戶(hù)可以完全不知道后面的改動(dòng),照常使用printf的功能.而你的LOG宏,只是規(guī)避了問(wèn)題,沒(méi)有解決我提出的log<<"hello"<<"world"無(wú)法判斷結(jié)束符的問(wèn)題,如果你有一種辦法,可以不改變我用戶(hù)的輸入,而解決這個(gè)問(wèn)題并且不帶來(lái)新的問(wèn)題,這個(gè)才算是解決吧.
2010-07-09 18:52 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@那誰(shuí)
不光是對(duì)于char型的不行,對(duì)于int、short使用%u輸出也不行,這是printf最致命的問(wèn)題。

你可以不承認(rèn)LOG宏是解決了你的問(wèn)題,但它是一個(gè)可以獲得期望行為的,保證輸出的正確性,而使用printf會(huì)導(dǎo)致程序錯(cuò)誤的輸出。

如果你非得要使用printf,給個(gè)建議,在自定義的函數(shù)內(nèi)檢查格式字符串,當(dāng)發(fā)現(xiàn)有%u時(shí),可以檢測(cè)它的值是正的還是負(fù)的,如果是負(fù)的可以給個(gè)警告或者拋出異常,保證行為的正確性。

不要在“規(guī)避”還是“解決”兩個(gè)詞之間找別扭了,保證程序的正確性才是根本。
printf會(huì)給你提供更多的出錯(cuò)機(jī)會(huì)
還要程序員時(shí)刻得著各個(gè)轉(zhuǎn)義字符的對(duì)應(yīng)關(guān)系,我是比較懶,我是記不住
而且__attribute__也只有GCC在新版本中擴(kuò)展功能才有,其它編譯器是不支持的
使用printf還會(huì)影響到使用std::string,這兩個(gè)混著用還經(jīng)常會(huì)忘了調(diào)用.c_str()方法,這樣在有些編譯器是安全的,但很多編譯器也會(huì)產(chǎn)生致命的錯(cuò)誤
使用printf如果參數(shù)比較多的話(huà)還容易造成順序錯(cuò)誤
2010-07-09 20:41 | Noock

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

@Noock
我文章的目的,是要說(shuō)明C++的這種機(jī)制存在缺陷,已經(jīng)強(qiáng)調(diào)了很多次.你可以"規(guī)避"這個(gè)問(wèn)題,不能否認(rèn)我的結(jié)論.
2010-07-09 20:50 | 那誰(shuí)

# re: C++的流設(shè)計(jì)很糟糕[未登錄](méi)  回復(fù)  更多評(píng)論   

沒(méi)太看明白。lz的意思是不是說(shuō)C++的流設(shè)計(jì)倒是用戶(hù)不能確定什么時(shí)候?qū)懭氲男畔?huì)真正流入到IO設(shè)備里,如果是這樣的話(huà)我覺(jué)得這種東西應(yīng)該放在文檔里。

stream << "abc" << "def" << endl; 這里你看不出來(lái)什么時(shí)候結(jié)束,
難道printf("%s%s\r\n", "abc", "def");你就能看出來(lái)了? 還不是要看文檔才知道?
2010-07-09 23:15 | 欲三更

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

服務(wù)器寫(xiě)log的,通常量不會(huì)太大,每次構(gòu)造一個(gè)對(duì)象也不會(huì)成為瓶頸吧;

我是這樣解決的,既可以保證類(lèi)型安全,也可以保證線(xiàn)程安全;
當(dāng)然如果你不用syslog自己寫(xiě)一個(gè)線(xiàn)程安全的flush函數(shù)也沒(méi)問(wèn)題啊

struct Log
{
int _lv;
std::stringstream _ss;

~Log()
{
syslog("%s\n", ss.str().data());
}

template<typename T1, typename T2, ... typename Tn>
Log(int lv, const T1 &t1, const T2 &t2, ... typename Tn)
: _lv(lv)
{
_ss << t1 << t2 << ... tn;
}
}

int main()
{
Log(info, "a=", 1, "; b=", 2);
}
2010-07-10 16:55 | 路過(guò)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

#define LOG(x) do{_log<<x<<endl;}while(0)

LOG(a<<b<<c<<d<<e);

這個(gè)呢,沒(méi)有了<<endl的問(wèn)題,編譯器也能檢查類(lèi)型。
2010-07-12 20:30 | 陳梓瀚(vczh)

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

雖然我不是很懂C++,但是我還是懂邏輯的。
后面幾個(gè)回復(fù)已經(jīng)答復(fù)了你的問(wèn)題。
C++的機(jī)制是最自然合理的處理方式。
其實(shí)出現(xiàn)問(wèn)題的原因是:實(shí)例里面的logstream并沒(méi)有按照C++ io的套路來(lái),
沒(méi)有加上一個(gè)結(jié)束的標(biāo)示: endl.
2010-07-28 22:20 | halida

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

感覺(jué)樓主對(duì)C++語(yǔ)言還缺乏較為深入的理解,下面對(duì)幾個(gè)問(wèn)題做點(diǎn)說(shuō)明,其實(shí)很簡(jiǎn)單,很多人不懂,是因?yàn)镃++標(biāo)準(zhǔn)教材沒(méi)這些東西。C++是一門(mén)在工業(yè)實(shí)踐中成長(zhǎng)起來(lái)的語(yǔ)言,工業(yè)界發(fā)明這些東西是因?yàn)樾枰瑢W(xué)院派卻總跟不上進(jìn)度,教材幾十年一變。要用C++,就要做好準(zhǔn)備,否則,你干嘛不用Java或者C#。

1. 關(guān)于所謂“頻繁的構(gòu)造/析構(gòu)開(kāi)銷(xiāo)大”
你首先要清楚“構(gòu)造”和“析構(gòu)”中編譯器到底為你做了什么。1.)分配對(duì)象空間:如果是在堆中分配對(duì)象,那么會(huì)有一個(gè)代價(jià)很大的堆分配(new,在2.7G的CPU上單線(xiàn)程new性能是5M次/秒);如果在堆棧上分配,內(nèi)存分配代價(jià)幾乎為零。2)調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù),這有兩個(gè)開(kāi)銷(xiāo),一個(gè)是調(diào)用本身的開(kāi)銷(xiāo),一個(gè)是函數(shù)體內(nèi)部代碼的開(kāi)銷(xiāo),很明顯,前者才C++帶來(lái)的額外開(kāi)銷(xiāo)。我可以告訴你的是,如果是內(nèi)聯(lián),這個(gè)開(kāi)銷(xiāo)為0,如果不是內(nèi)聯(lián),這個(gè)開(kāi)銷(xiāo)在2.7G的CPU上單線(xiàn)程性能是1200M次/秒,作為類(lèi)比,2.7G的CPU上單線(xiàn)程可以做400M次32位整型變量寫(xiě)入操作,也就是這個(gè)開(kāi)銷(xiāo)比寫(xiě)一個(gè)整型變量還小。
現(xiàn)在,看看你說(shuō)的情況,局部對(duì)象的構(gòu)造和析構(gòu),每次的代價(jià)比寫(xiě)一個(gè)32位整型的變量還小得多,相比每次日志輸出至少十幾個(gè)字節(jié)的內(nèi)存拷貝,這點(diǎn)開(kāi)銷(xiāo)完全可以忽略不計(jì),除非打算每秒中打算做1M次的日志,它帶來(lái)的代價(jià)不占用1%的CPU而已,不過(guò)事實(shí)是,每秒鐘寫(xiě)不了1M次的文件IO。
最后從設(shè)計(jì)的角度考慮這個(gè)問(wèn)題,你的系統(tǒng)打算每秒中寫(xiě)多少次日志,應(yīng)該心理有數(shù)吧,從這個(gè)意義上,從設(shè)計(jì)的角度,上面我寫(xiě)的那些分析毫無(wú)必要,只是為了加深對(duì)C++的理解,事實(shí)是,即便“頻繁的構(gòu)造/析構(gòu)開(kāi)銷(xiāo)大”很大,它們?nèi)匀徊皇窍到y(tǒng)的真正瓶頸,沒(méi)必要過(guò)早優(yōu)化。如果它們真成了瓶頸,你應(yīng)該做的事情是,調(diào)整成合理的日志策略。





2010-08-03 22:20 | maxime

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

2.所謂“比如log << "hello " << "world",是無(wú)法判斷到底在輸出"hello"還是"world"的時(shí)候上面的參數(shù)輸入已經(jīng)結(jié)束了”

其實(shí),這個(gè)問(wèn)題,流的設(shè)計(jì)者早已考慮到了,std::endl就是用來(lái)干這件事情的。事實(shí)上,自定義的流操控符,還可以干很多事情比如:
std::cout << v1 << mylock(v2) << v2 << myunlock(v2);
上面的mylock,myunlock就是自定義的操作符,用來(lái)給v2加鎖解鎖,而不輸出任何字符。它到底能做什么,取決于你的想象力。我總愛(ài)把C++比作機(jī)械行業(yè)的鉗工,他們比不上機(jī)器的速度,但沒(méi)他們不行,很多事情機(jī)器做不了。使用正確的工具做正確的事情,如果你感覺(jué)不對(duì),先想想選對(duì)工具沒(méi),而不是抱怨工具很爛。

額外,說(shuō)明一點(diǎn),有人告訴你sprintf存在寫(xiě)錯(cuò)的可能性,所以,你可以說(shuō),如果別人忘了寫(xiě)上他的endl怎么辦?

我來(lái)告訴你吧,寫(xiě)錯(cuò)了其實(shí)沒(méi)什么大不了的,問(wèn)題關(guān)鍵是,寫(xiě)錯(cuò)了會(huì)帶來(lái)什么危害。sprintf寫(xiě)錯(cuò)了,可能帶來(lái)的是內(nèi)存溢出覆蓋,這才是我們恐懼他的原因,一個(gè)內(nèi)存溢出帶來(lái)的危害我就不說(shuō)了。
反之,少寫(xiě)了一個(gè)endl,最多就是兩行日志重疊,或者一個(gè)日志輸出時(shí)間晚了一會(huì)兒。如果你真看到這個(gè)情況,把endl加上去就行了。

不知道現(xiàn)在是否能理解了,不要害怕bug,不要害怕寫(xiě)錯(cuò),要怕會(huì)讓你掉進(jìn)深淵的bug。我得承認(rèn),這是C/C++的弱點(diǎn),java/C#相對(duì)好很多。
C++最害怕的,就是指針操作,內(nèi)存覆蓋可以毀掉整個(gè)程序的運(yùn)行基礎(chǔ),卻不容易找到錯(cuò)誤的代碼。但這也是C++的優(yōu)點(diǎn),C++為什么要用流替換C的sprintf,就是要減少內(nèi)存覆蓋錯(cuò)誤的機(jī)會(huì)。當(dāng)然,C++中仍然有這種錯(cuò)誤的機(jī)會(huì),因?yàn)閽仐壛酥羔槪珻++和Java就沒(méi)區(qū)別了。如果說(shuō)C是做操作系統(tǒng)的,java是做應(yīng)用的,C++就是做系統(tǒng)和應(yīng)用結(jié)合部的,只有理解了這點(diǎn),你才能用好C++,而不是抱怨,它既沒(méi)C簡(jiǎn)單,也沒(méi)java安全。
事實(shí)是,C++就是這么個(gè)怪胎,比Java更快,比C更安全更有開(kāi)發(fā)效率。



















2010-08-03 22:38 | maxime

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

3. 關(guān)于“要使用這門(mén)語(yǔ)言寫(xiě)出正確的程序來(lái),需要了解底下多少的細(xì)節(jié)呢?!”

首先答案是,不需要知道細(xì)節(jié),只需要知道“規(guī)范”。C++真正的問(wèn)題不是太復(fù)雜,而是在實(shí)踐中缺乏規(guī)范,尤其在中國(guó)的軟件作坊里面。就像你會(huì)開(kāi)汽車(chē)一樣的,你沒(méi)比要知道汽車(chē)發(fā)動(dòng)機(jī)原理,同樣能把汽車(chē)開(kāi)好。因?yàn)槟阕袷亓碎_(kāi)汽車(chē)的規(guī)范,比如啟動(dòng)的時(shí)候,慢加油門(mén)。

很多人的問(wèn)題在于,在思想上,忽視了規(guī)范,到頭來(lái)卻怪東西太復(fù)雜。

其次是了解細(xì)節(jié),可以工作更深入。再說(shuō)了,就算復(fù)雜,C++能有多復(fù)雜,一個(gè)C++語(yǔ)言里面能有多少東西呢?相比一個(gè)Java庫(kù),這點(diǎn)東西真算不了什么。很多人掌握不好,是因?yàn)闆](méi)有正正經(jīng)經(jīng)的機(jī)會(huì)去學(xué),去練。這點(diǎn)像數(shù)學(xué),學(xué)的時(shí)候比較枯燥,不管怎么說(shuō),這點(diǎn)東西就叫復(fù)雜,那只能說(shuō),做的應(yīng)用系統(tǒng)太簡(jiǎn)單。
2010-08-03 22:50 | maxime

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

4. 關(guān)于“假如需要考慮多線(xiàn)程的話(huà),那么一次輸入有多個(gè)函數(shù)函數(shù)中被調(diào)用”

要在多線(xiàn)程進(jìn)行IO操作,肯定是要用鎖的,就算你不直接用,系統(tǒng)API的流API,比如Win32的WriteFile,也是要用的。


所以,答案很簡(jiǎn)單,用鎖。問(wèn)題不在于有幾次函數(shù)調(diào)用,而在于能否讓這幾次函數(shù)調(diào)用位于同一個(gè)鎖當(dāng)中。

傳統(tǒng)上,一個(gè)sprinf,你可以加一次鎖,就夠了。
而現(xiàn)在呢,分成了好幾次調(diào)用,那么就在這幾次調(diào)用之間和之后加鎖就行了,在本例中,也就是那個(gè)被認(rèn)為過(guò)于調(diào)用繁瑣的臨時(shí)對(duì)象了,在它的構(gòu)造函數(shù)加鎖,在它的析構(gòu)函數(shù)中解鎖,就能保證輸出的原子性。如果這樣還不滿(mǎn)意,還可以考慮流操控符加鎖,不過(guò)有點(diǎn)危險(xiǎn)。


不過(guò)呢,說(shuō)道最后,如果你明白,那個(gè)看似效率低下的臨時(shí)對(duì)象其實(shí)對(duì)整行的輸出做了緩存,所以在glog中,臨時(shí)對(duì)象中是沒(méi)必要用鎖的,因?yàn)榕R時(shí)對(duì)象中保存的字串是不會(huì)被多線(xiàn)程打斷的,它能夠保證所有的“<<”調(diào)用在輸出上的原子性。最后析構(gòu)函數(shù)中,真正進(jìn)行輸出時(shí),在下層的實(shí)際輸出位置,實(shí)際上是有鎖。



2010-08-04 00:03 | maxime

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

5. 最后談一下,C++流的真正缺點(diǎn)?

從安全性的角度講,C++流相對(duì)sprintf是一次飛躍。從實(shí)際項(xiàng)目來(lái)看,C++程序員的代碼產(chǎn)出和維護(hù)量,通常會(huì)數(shù)倍甚至幾十倍于C程序員,這表面了在某些問(wèn)題域上,C++比更有開(kāi)發(fā)效率。

但由此帶來(lái)的問(wèn)題是,在代碼量少的時(shí)候,C程序員可以花時(shí)間慢慢檢查代碼,保證sprintf沒(méi)問(wèn)題。而C++程序員再這樣做效率就太低了。所以才會(huì)有了C++流的方案,C++流設(shè)計(jì)者正是從實(shí)踐中品嘗到了sprintf的苦果。

事實(shí)是,C++語(yǔ)法形式,從實(shí)用性角度,的確很蹩腳。而且性能只有sprintf的1/3.不過(guò)實(shí)際環(huán)境下,性能通常不是問(wèn)題,流輸出很少會(huì)是一個(gè)應(yīng)用系統(tǒng)真正的瓶頸。

蹩腳的語(yǔ)法,是個(gè)問(wèn)題,尤其當(dāng)你需要做格式控制的時(shí)候,代碼可能非常長(zhǎng)。這個(gè)問(wèn)題,我的看法是,寫(xiě)的時(shí)候可能多花點(diǎn)時(shí)間,不過(guò)以后維護(hù)起來(lái)就輕松了。畢竟,我寧愿選擇安全性,花三天時(shí)間去找一個(gè)緩沖區(qū)溢出是不會(huì)寧人愉悅的。當(dāng)你認(rèn)為語(yǔ)法問(wèn)題很重要時(shí),通常暗示代碼管理上有問(wèn)題。我通常認(rèn)為代碼的書(shū)寫(xiě)只占20%的時(shí)間,80%時(shí)間是在維護(hù)代碼。維護(hù)效率遠(yuǎn)比書(shū)寫(xiě)效率重要。

在C++領(lǐng)域,新發(fā)明似乎是沒(méi)有止境的,有一個(gè)新的,利用重載“()”操作符的格式化庫(kù)出現(xiàn)了,具體我本人沒(méi)有用過(guò),看起來(lái)還不錯(cuò),據(jù)說(shuō)在性能上優(yōu)于sprintf,在安全性上不輸于C++流,在格式上類(lèi)似sprintf。由于缺乏大規(guī)模應(yīng)用,實(shí)際情況如何,還不好說(shuō)。


就我本人而言,我認(rèn)為C++流的效率和格式問(wèn)題,并非致命問(wèn)題,所以也就不急著使用更先進(jìn)的東西了,短期內(nèi)我C++流仍是最好的格式化輸出工具。除非,項(xiàng)目主要業(yè)務(wù)邏輯就是格式化字符串,那也許我會(huì)選擇sprintf或者其他的東西。















2010-08-04 00:22 | maxime

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

最后,我感覺(jué)樓主,似乎想在一個(gè)輸出語(yǔ)句中,輸出很長(zhǎng)很長(zhǎng)的,可能跨越多次物理輸出的內(nèi)容。

這樣做,首先代碼不易理解,不易修改維護(hù)。

根據(jù)本人的實(shí)際經(jīng)驗(yàn)來(lái)看,日志輸出最好還是按實(shí)際物理行為單位比較好,所以glog沒(méi)有支持所謂endl特性。

樓主可能真正擔(dān)心的是另一個(gè)問(wèn)題,在多線(xiàn)程程環(huán)境下,想要連續(xù)輸出的幾行文本,會(huì)被其他線(xiàn)程打斷,以致閱讀性變差。

對(duì)此,我建議,如果不希望被打斷,使用glog那就需要八幾行輸出寫(xiě)在一個(gè)glog句子,作為一次原子輸出就行了。但是,如果樓主對(duì)這樣的原子輸出,還要求再被分成多次物理輸出,那這是為什么呢?有這個(gè)必要嗎?既然打算連續(xù)輸出幾行,且在一個(gè)語(yǔ)句之中,整個(gè)語(yǔ)句時(shí)間是非常快的,對(duì)觀察者而言,一次原子輸出是由一次物理輸出還是多次物理輸出構(gòu)成,沒(méi)有任何實(shí)際意義。








2010-08-04 00:36 | maxime

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

剛才服務(wù)器崩潰了,估計(jì)又是(我是用)printf的(問(wèn)題)。譬如%s,結(jié)果我的參數(shù)為int型別。
之前測(cè)試程序時(shí),就出過(guò)這類(lèi)錯(cuò)誤。不過(guò)解決倒也容易。
2010-08-26 21:29 | 哭啊

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

都是大神
2010-10-29 14:55 | 刀刀

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

在CPP 博客批CPP
哈哈 找抽

懂c++的c太他們簡(jiǎn)單的玩意
2010-12-27 14:11 | 法國(guó)風(fēng)格

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

Set your life time more simple take the <a href="http://bestfinance-blog.com">loans</a> and everything you need.
2011-09-02 12:52 | CecileOneal25

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

很不錯(cuò)。
2011-09-08 23:25 | tall ugg outlet

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

你們都弱爆了,想想這樣的log api是怎么實(shí)現(xiàn)的

jj_log(0, (%p, fd)(%d, backlog)((eh_format), er));

jj_log(4, "ERROR: %d", er);
2011-11-01 09:42 | tankxx

# re: C++的流設(shè)計(jì)很糟糕  回復(fù)  更多評(píng)論   

超級(jí)牛掰的一群人啊。。。佩服
2011-11-23 13:07 | 煙圈
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲一区二区av电影| 欧美亚洲综合久久| 亚洲精品一区二区三区av| 欧美性大战久久久久| 另类亚洲自拍| 国产精品欧美久久| 模特精品裸拍一区| 欧美午夜精品理论片a级大开眼界| 亚洲欧美国产高清va在线播| 米奇777超碰欧美日韩亚洲| 一区二区高清在线| 久久久久女教师免费一区| 亚洲香蕉网站| 99综合在线| 牛夜精品久久久久久久99黑人 | 欧美www视频| 久久亚洲影音av资源网| 国产精品色在线| 99在线观看免费视频精品观看| 激情小说另类小说亚洲欧美| 亚洲欧美日韩中文播放| 亚洲一区欧美二区| 欧美日韩国产一区精品一区| 亚洲欧洲精品一区二区| 亚洲高清不卡在线| 奶水喷射视频一区| 亚洲国产一区在线观看| 99国产精品视频免费观看| 欧美精品一区二区三区久久久竹菊 | 免费在线亚洲欧美| 精品不卡在线| 欧美电影免费观看网站| 亚洲日本理论电影| 久久精品视频在线播放| 亚洲乱码视频| 海角社区69精品视频| 久久综合影视| 亚洲欧美日韩精品久久亚洲区| 久久亚洲二区| 亚洲夜晚福利在线观看| 国产一区免费视频| 欧美日本三区| 久久精品国产亚洲精品| 亚洲电影中文字幕| 久久午夜精品一区二区| 亚洲调教视频在线观看| 黄色成人在线网址| 国产精品美女| 欧美紧缚bdsm在线视频| 久久久国产视频91| 午夜精品久久久99热福利| 91久久嫩草影院一区二区| 久久看片网站| 久久久爽爽爽美女图片| 欧美伊久线香蕉线新在线| 亚洲精品在线免费| 一区二区三区在线免费播放| 久久精品99国产精品酒店日本| 一区二区三区毛片| 亚洲一区二区伦理| 一区二区三区毛片| 一区二区三区久久网| 亚洲午夜羞羞片| 午夜精品久久久99热福利| 亚洲欧美中文日韩在线| 这里只有视频精品| 欧美日韩影院| 国产精品免费一区二区三区在线观看 | 性欧美video另类hd性玩具| 亚洲九九爱视频| 日韩视频不卡| 午夜精品网站| 亚洲中字黄色| 久久国产精品99国产| 一区二区三区蜜桃网| 日韩网站在线观看| 一区二区三区精品视频| 一区二区三区四区五区精品视频| 亚洲视频在线观看三级| 欧美一区二区三区电影在线观看| 蜜桃精品久久久久久久免费影院| 亚洲巨乳在线| 久久男女视频| 国产精品视频网址| 亚洲免费av片| 欧美永久精品| 亚洲国产精品综合| 欧美一区二区在线播放| 欧美视频国产精品| 亚洲精品美女| 另类图片国产| 久久久噜噜噜久久中文字幕色伊伊| 国产精品综合不卡av| 欧美制服丝袜第一页| 99ri日韩精品视频| 激情欧美日韩| 日韩一区二区福利| 国产噜噜噜噜噜久久久久久久久| 亚洲男人第一av网站| 亚洲在线中文字幕| 狠狠色狠狠色综合人人| 久久精品久久99精品久久| 亚洲欧美日韩在线综合| 久久亚洲影音av资源网| 欧美在线观看www| 国产美女精品视频| 久久免费视频网| 欧美一区二区视频免费观看| 黄色成人免费观看| 日韩网站在线看片你懂的| 欧美激情视频一区二区三区在线播放 | 欧美日韩mv| 午夜精品久久| 久久国产精品亚洲va麻豆| 在线观看成人av| 亚洲国产精品电影| 欧美三级视频在线播放| 久久午夜精品| 欧美日韩激情小视频| 久久久天天操| 国产精品网站在线| 一区二区三区成人| 亚洲一区二区三区三| 欧美日韩一区在线观看| 亚洲精品自在久久| 日韩亚洲视频| 国产精品福利在线| 亚洲国产午夜| 亚洲第一精品夜夜躁人人躁| 日韩亚洲不卡在线| 日韩亚洲欧美高清| 免费人成网站在线观看欧美高清| 亚洲免费视频中文字幕| 欧美精品久久久久久久免费观看| 欧美成人亚洲| 亚洲欧洲精品一区二区| 久久久久久一区| 久久综合色播五月| 国内一区二区三区| 久久久久久亚洲综合影院红桃 | 亚洲欧洲综合另类| 中国亚洲黄色| 亚洲一区二区三区四区中文| 免费成人在线视频网站| 一区二区三区色| 亚洲国产精品视频一区| 午夜视频久久久久久| 香蕉久久夜色精品国产| 国产精品区一区| 午夜国产欧美理论在线播放 | 亚洲福利在线看| 亚洲日产国产精品| 欧美日韩国产一区精品一区 | 久久黄金**| 蜜臀久久99精品久久久久久9| 在线看片成人| 欧美伦理在线观看| 久久久综合网| 一区二区三区www| 久久综合给合| 亚洲欧美一区二区三区在线| 国产精品揄拍500视频| 鲁大师成人一区二区三区| 一区二区高清在线观看| 另类图片综合电影| 亚洲欧美中文在线视频| 亚洲人线精品午夜| 黄色国产精品| 国产欧美综合一区二区三区| 欧美成人免费播放| 久久久一本精品99久久精品66| 在线视频欧美一区| 亚洲综合精品四区| 亚洲一级电影| 亚洲国产欧美久久| 久久久不卡网国产精品一区| 亚洲少妇一区| 99re亚洲国产精品| 91久久精品国产91久久性色| 国产日韩欧美一区| 久久久美女艺术照精彩视频福利播放| 欧美不卡一区| 欧美国产日韩在线| 女同性一区二区三区人了人一 | 亚洲第一在线视频| 亚洲国产另类久久精品| 欧美激情中文字幕一区二区| 亚洲高清久久| 亚洲一级特黄| 鲁大师成人一区二区三区| 免费视频久久| 国产精品videosex极品| 国产亚洲福利一区| 在线观看视频欧美| 妖精成人www高清在线观看| 亚久久调教视频| 亚洲国产精品福利| 欧美一级理论片| 欧美人与性动交α欧美精品济南到| 欧美日韩国产综合一区二区|