我是初學C++程序員,所以我學會了使用數組而不是向量(這似乎是做事的一般方法,然後再轉向向量)。何時使用數組而不是矢量/字符串?
我注意到很多關於SO的答案都建議在數組上使用向量,而在char數組上使用字符串。看起來,這是用C++編寫的「正確」方式。
這一切都說,它仍然值得使用經典的數組/字符*(如果有的話)?
我是初學C++程序員,所以我學會了使用數組而不是向量(這似乎是做事的一般方法,然後再轉向向量)。何時使用數組而不是矢量/字符串?
我注意到很多關於SO的答案都建議在數組上使用向量,而在char數組上使用字符串。看起來,這是用C++編寫的「正確」方式。
這一切都說,它仍然值得使用經典的數組/字符*(如果有的話)?
在編寫應該在其他項目中使用的代碼時,特別是如果您將目標鎖定在STL可能不存在的特殊平臺(嵌入式,遊戲控制檯等)時。
舊項目或有特殊要求的項目可能不想引入STL庫的依賴關係。一個接口依賴於數組,char *或任何與任何東西都兼容的接口,因爲它是語言的一部分。但是,STL並不保證在所有構建環境中都存在。
我建議在編譯時自己知道大小的時候使用數組。儘管可以使用向量,但我們必須記住,向量帶有與在堆上完成的內存分配相關的開銷。如果大小不知道,那麼當然使用向量。
當兼容性或性能具有非常高的優先級時,Array/char *很有用。向量和字符串是代碼可維護性,可讀性和整體易用性都更好的更高級對象。幾乎總是這樣。
我能想到的唯一原因就是速度。您可以對數組/指針類型進行更好的優化,而不是根據對象進行優化。但是如果我絕對知道數據結構需要保存的數據量,我甚至會使用STL。在優化步驟中從STL改爲原始類型比使用難以閱讀的代碼啓動項目要好。
我看到兩個方面的原因:
從來沒有。
如果原始陣列似乎比的載體更好的解決方案(原因其他這裏所述),那麼我使用的std :: TR1 ::陣列或std ::陣列中的C++編譯器11(或boost::array )。 它只是做我會做的檢查,以確保和尺寸值的使用使DRY自動實現(例如我在循環中使用大小,以便將來的數組變化聲明將自動工作)。
這是數組實現「是」的原始數組,其檢查和提供的大小始終保持不變,所以很容易在嵌入式代碼中獲取數組代碼,因爲對於任何編譯器而言都是the code is not really "too smart"。就編譯器支持模板而言,我會在我的代碼中複製boost頭文件,以允許我使用這個代替原始數組。因爲原始數組很容易出錯。 Raw arrays are evil.他們很容易出錯。
它與STL算法(如果可用)非常協調。
現在,有兩種情況下,你需要到使用原始陣列(義務):當你在C-唯一代碼(不是C代碼進行通信,但在編寫C-唯一代碼的一部分,就像一個C庫)。但是,這是另一種語言。
另一個原因是,當編譯器根本就不支持模板...
這個問題實際上可以分爲兩個部分:
我個人更喜歡使用std ::矢量用於管理存儲器的情況除外我需要保持與代碼不使用STL兼容性(即,當具有直的C代碼接口)。這是更難做異常安全代碼通過新的或的malloc分配的原始陣列(部分是因爲它真的很容易忘記,你不必擔心它)。有關原因,請參閱RAII上的任何文章。
在實踐中,的std ::矢量被實施爲扁平陣列。因此,總是可以拉出原始數組並使用C風格的訪問模式。我通常從矢量下標運算符語法開始。對於某些編譯器,在生成調試版本時,向量會自動提供邊界檢查。這很慢(對於緊密循環而言通常會減慢10倍),但對尋找某些類型的錯誤很有幫助。
如果在特定平臺上分析表明該操作符[]是一個瓶頸,然後切換到直接訪問原始陣列。有趣的是,根據不同的編譯器和OS,它有時可以更快地使用一個STL矢量不是原始陣列。
下面是一個簡單的測試應用程序的一些結果。它使用Visual Studio 2008在32位發佈模式下使用/ O2優化進行編譯,並在Vista x64上運行。使用64位測試應用程序可以獲得類似的結果。
Binary search...
fill vector (for reference) : 0.27 s
array with ptr math : 0.38 s <-- C-style pointers lose
array with int index : 0.23 s <-- [] on raw array wins
array with ptrdiff_t index : 0.24 s
vector with int index : 0.30 s <-- small penalty for vector abstraction
vector with ptrdiff_t index : 0.30 s
Counting memory (de)allocation...
memset (for reference) : 2.85 s
fill malloc-ed raw array with [] : 2.66 s
fill malloc-ed raw array with ptr : 2.81 s
fill new-ed raw array with [] : 2.64 s
fill new-ed raw array with ptr : 2.65 s
fill vector as array : 3.06 s \ something's slower
fill vector : 3.05 s/with vector!
NOT counting memory (de)allocation...
memset (for reference) : 2.57 s
fill malloc-ed raw array with [] : 2.86 s
fill malloc-ed raw array with ptr : 2.60 s
fill new-ed raw array with [] : 2.63 s
fill new-ed raw array with ptr : 2.78 s
fill vector as array : 2.49 s \ after discounting the
fill vector : 2.54 s/(de)allocation vector is faster!
代碼:
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#include <string>
#include <vector>
#include <stdio.h>
using namespace std;
__int64 freq; // initialized in main
int const N = 1024*1024*1024/sizeof(int)/2; // 1/2 GB of data
int const nIter = 10;
class Timer {
public:
Timer(char *name) : name(name) {
QueryPerformanceCounter((LARGE_INTEGER*)&start);
}
~Timer() {
__int64 stop;
QueryPerformanceCounter((LARGE_INTEGER*)&stop);
printf(" %36s : % 4.2f s\n", name.c_str(), (stop - start)/double(freq));
}
private:
string const name;
__int64 start;
};
template <typename Container, typename Index>
int binarySearch_indexed(Container sortedArray, Index first, Index last, int key) {
while (first <= last) {
Index mid = (first + last)/2; // NOT safe if (first+last) is too big!
if (key > sortedArray[mid]) first = mid + 1;
else if (key < sortedArray[mid]) last = mid - 1;
else return mid;
}
return 0; // Use "(Index)-1" in real code
}
int Dummy = -1;
int const *binarySearch_ptr(int const *first, int const *last, int key) {
while (first <= last) {
int const *mid = (int const *)(((unsigned __int64)first + (unsigned __int64)last)/2);
if (key > *mid) first = mid + 1;
else if (key < *mid) last = mid - 1;
else return mid;
}
return &Dummy; // no NULL checks: don't do this for real
}
void timeFillWithAlloc() {
printf("Counting memory (de)allocation...\n");
{
Timer tt("memset (for reference)");
int *data = (int*)malloc(N*sizeof(int));
for (int it=0; it<nIter; it++) memset(data, 0, N*sizeof(int));
free(data);
}
{
Timer tt("fill malloc-ed raw array with []");
int *data = (int*)malloc(N*sizeof(int));
for (int it=0; it<nIter; it++) for (size_t i=0; i<N; i++) data[i] = (int)i;
free(data);
}
{
Timer tt("fill malloc-ed raw array with ptr");
int *data = (int*)malloc(N*sizeof(int));
for (int it=0; it<nIter; it++) {
int *d = data;
for (size_t i=0; i<N; i++) *d++ = (int)i;
}
free(data);
}
{
Timer tt("fill new-ed raw array with []");
int *data = new int[N];
for (int it=0; it<nIter; it++) for (size_t i=0; i<N; i++) data[i] = (int)i;
delete [] data;
}
{
Timer tt("fill new-ed raw array with ptr");
int *data = new int[N];
for (int it=0; it<nIter; it++) {
int *d = data;
for (size_t i=0; i<N; i++) *d++ = (int)i;
}
delete [] data;
}
{
Timer tt("fill vector as array");
vector<int> data(N);
for (int it=0; it<nIter; it++) {
int *d = &data[0];
for (size_t i=0; i<N; i++) *d++ = (int)i;
}
}
{
Timer tt("fill vector");
vector<int> data(N);
for (int it=0; it<nIter; it++) for (size_t i=0; i<N; i++) data[i] = (int)i;
}
printf("\n");
}
void timeFillNoAlloc() {
printf("NOT counting memory (de)allocation...\n");
{
int *data = (int*)malloc(N*sizeof(int));
{
Timer tt("memset (for reference)");
for (int it=0; it<nIter; it++) memset(data, 0, N*sizeof(int));
}
free(data);
}
{
int *data = (int*)malloc(N*sizeof(int));
{
Timer tt("fill malloc-ed raw array with []");
for (int it=0; it<nIter; it++) for (size_t i=0; i<N; i++) data[i] = (int)i;
}
free(data);
}
{
int *data = (int*)malloc(N*sizeof(int));
{
Timer tt("fill malloc-ed raw array with ptr");
for (int it=0; it<nIter; it++) {
int *d = data;
for (size_t i=0; i<N; i++) *d++ = (int)i;
}
}
free(data);
}
{
int *data = new int[N];
{
Timer tt("fill new-ed raw array with []");
for (int it=0; it<nIter; it++) for (size_t i=0; i<N; i++) data[i] = (int)i;
}
delete [] data;
}
{
int *data = new int[N];
{
Timer tt("fill new-ed raw array with ptr");
for (int it=0; it<nIter; it++) {
int *d = data;
for (size_t i=0; i<N; i++) *d++ = (int)i;
}
}
delete [] data;
}
{
vector<int> data(N);
{
Timer tt("fill vector as array");
for (int it=0; it<nIter; it++) {
int *d = &data[0];
for (size_t i=0; i<N; i++) *d++ = (int)i;
}
}
}
{
vector<int> data(N);
{
Timer tt("fill vector");
for (int it=0; it<nIter; it++) for (size_t i=0; i<N; i++) data[i] = (int)i;
}
}
printf("\n");
}
void timeBinarySearch() {
printf("Binary search...\n");
vector<int> data(N);
{
Timer tt("fill vector (for reference)");
for (size_t i=0; i<N; i++) data[i] = (int)i;
}
{
Timer tt("array with ptr math");
int sum = 0;
for (int i=-1000000; i<1000000; i++) {
sum += *binarySearch_ptr(&data[0], &data[0]+data.size(), i);
}
}
{
Timer tt("array with int index");
int sum = 0;
for (int i=-1000000; i<1000000; i++) {
sum += data[binarySearch_indexed<int const *, int>(
&data[0], 0, (int)data.size(), -1)];
}
}
{
Timer tt("array with ptrdiff_t index");
int sum = 0;
for (int i=-1000000; i<1000000; i++) {
sum += data[binarySearch_indexed<int const *, ptrdiff_t>(
&data[0], 0, (ptrdiff_t)data.size(), -1)];
}
}
{
Timer tt("vector with int index");
int sum = 0;
for (int i=-1000000; i<1000000; i++) {
sum += data[binarySearch_indexed<vector<int> const &, int>(
data, 0, (int)data.size(), -1)];
}
}
{
Timer tt("vector with ptrdiff_t index");
int sum = 0;
for (int i=-1000000; i<1000000; i++) {
sum += data[binarySearch_indexed<vector<int> const &, ptrdiff_t>(
data, 0, (ptrdiff_t)data.size(), -1)];
}
}
printf("\n");
}
int main(int argc, char **argv)
{
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
timeBinarySearch();
timeFillWithAlloc();
timeFillNoAlloc();
return 0;
}
我就需要訪問結構化數據共享庫工作。這些數據在編譯時已知,因此它使用POD(普通舊數據)結構的文件範圍常量數組來保存數據。
這將導致編譯器和鏈接器將大部分數據在只讀段,有兩個好處:
唯一的例外是編譯器仍然生成初始化代碼來加載浮點常量,因此任何包含浮點數的結構都會以可寫入節結束。我懷疑這與浮動異常或浮點舍入模式有關,但我不知道如何驗證任何假設。
如果我用這個vector和string對象,那麼編譯器會生成更多的初始化代碼,每當我的共享庫被加載,將執行。常量數據將分配在堆上,因此它不會在進程之間共享。
如果我讀了從磁盤上的文件中的數據,我將不得不應付檢查的數據格式,而不是具有C++編譯器爲我做的。我還必須管理一個代碼庫中的數據的生命週期,這個數據庫從一開始就將這個全局數據「燒入」了它。
您也可以使用boost ::數組或TR1 ::陣列。 – Anonymous 2009-02-27 12:42:47
複製開銷如何與數組不同?我能想到的地方陣列會更有效率的唯一情況是,如果你有「富ARR [] = {美孚(...),美孚(...),...};」 – 2009-02-27 13:09:50
@Mr Fooz:是的,你是對的。沒有區別。我編輯了我的答案。 – Naveen 2009-02-27 13:41:39