2011-01-30 59 views
5

Tôi đã tự hỏi liệu (ngoài sự khác biệt cú pháp rõ ràng) sẽ có sự khác biệt về hiệu quả giữa việc có một lớp chứa nhiều phiên bản của một đối tượng (cùng loại) hoặc cố định mảng kích thước của các đối tượng thuộc loại đó.C++ mảng kích thước cố định so với nhiều đối tượng cùng loại

Trong mã:

struct A { 
    double x; 
    double y; 
    double z; 
}; 

struct B { 
    double xvec[3]; 
}; 

Trên thực tế tôi sẽ được sử dụng tăng :: mảng mà là một tốt hơn C++ thay thế cho mảng C-phong cách.

Tôi chủ yếu quan tâm đến việc xây dựng/hủy và đọc/ghi như vậy đôi, bởi vì các lớp này thường sẽ được xây dựng chỉ để gọi một trong các chức năng thành viên của họ một lần.

Cảm ơn sự giúp đỡ/đề xuất của bạn.

+3

mảng cho phép lặp qua giá trị của chúng, điều này là không thể khi sử dụng thành viên riêng lẻ – Christoph

+1

Bất cứ khi nào bạn có câu hỏi về hiệu suất/hiệu suất, hãy viết một ứng dụng thử nghiệm nhỏ và so sánh. Nếu bạn gặp khó khăn khi giải thích kết quả, hãy đặt câu hỏi. –

Trả lời

8

Thông thường, việc trình bày hai cấu trúc đó sẽ giống hệt nhau. Tuy nhiên, có thể có hiệu suất kém nếu bạn chọn sai số cho trường hợp sử dụng của mình.

Ví dụ, nếu bạn cần truy cập mỗi phần tử trong vòng một, với một mảng bạn có thể làm:

for (int i = 0; i < 3; i++) 
    dosomething(xvec[i]); 

Tuy nhiên, không một mảng, bạn muốn hoặc cần phải lặp mã:

dosomething(x); 
dosomething(y); 
dosomething(z); 

Điều này có nghĩa là sao chép mã - có thể theo một trong hai cách. Một mặt có ít mã vòng lặp hơn; Mặt khác các vòng rất chặt chẽ có thể khá nhanh trên các bộ vi xử lý hiện đại, và sự sao chép mã có thể thổi bay bộ đệm I-cache.

Các tùy chọn khác là một chuyển đổi:

for (int i = 0; i < 3; i++) { 
    int *r; 
    switch(i) { 
     case 0: r = &x; break; 
     case 1: r = &y; break; 
     case 1: r = &z; break; 
    } 
    dosomething(*r); // assume this is some big inlined code 
} 

này tránh được dấu chân i-cache có thể lớn, nhưng có một tác động hiệu quả tiêu cực rất lớn. Đừng làm thế.

Mặt khác, nó là, về nguyên tắc, có thể cho mảng truy cập chậm hơn, nếu trình biên dịch của bạn không phải là rất thông minh:

xvec[0] = xvec[1] + 1; 
dosomething(xvec[1]); 

Kể từ xvec [0] và xvec [1] là khác biệt, về nguyên tắc, trình biên dịch phải có khả năng giữ giá trị của xvec [1] trong một thanh ghi, vì vậy nó không phải tải lại giá trị ở dòng kế tiếp. Tuy nhiên, có thể một số trình biên dịch có thể không đủ thông minh để nhận thấy rằng xvec [0] và xvec [1] không bí danh. Trong trường hợp này, việc sử dụng các trường riêng biệt có thể nhanh hơn một chút.

Tóm lại, nó không phải là một hoặc cái kia nhanh trong mọi trường hợp. Đó là về kết hợp các đại diện cho cách bạn sử dụng nó.

Cá nhân, tôi khuyên bạn nên làm theo bất kỳ điều gì làm cho mã hoạt động trên xvec tự nhiên nhất. Nó không có giá trị dành nhiều thời gian của con người đáng lo ngại về một cái gì đó, tốt nhất, có lẽ sẽ chỉ tạo ra một sự khác biệt hiệu suất nhỏ mà bạn sẽ chỉ bắt nó trong tiêu chuẩn vi.

1

Điều đó tùy thuộc. Ví dụ, ví dụ bạn đã là một trong những cổ điển thiên về mảng 'cũ-trường': một toán điểm/vector (hoặc ma trận)

  • có một số cố định của các yếu tố
  • chính dữ liệu thường là giữ tư nhân trong một đối tượng
  • từ (nếu?) nó có một lớp như một giao diện , bạn đúng có thể khởi tạo chúng trong constructor (nếu không, mảng kinh điển inialization là một cái gì đó tôi không thực sự thích, cú pháp khôn ngoan)

Trong trường hợp như vậy (đi với các ví dụ về ma trận/ma trận toán), tôi luôn sử dụng các mảng kiểu C trong nội bộ, vì bạn có thể lặp lại chúng thay vì viết mã sao chép/dán cho mỗi thành phần.

Nhưng đây là một trường hợp đặc biệt - đối với tôi, trong C++ hiện nay mảng == vector STL, nó nhanh chóng và tôi không phải lo lắng về nuthin' :)

+0

Có sự khác biệt giữa 'std :: vector ' và 'std :: array ', vì vậy tôi sẽ không cân bằng mảng với vectơ. – fredoverflow

-1

mảng thô cung cấp địa phương tốt hơn so với bộ nhớ cache C++ mảng, như được trình bày tuy nhiên, lợi thế duy nhất của ví dụ mảng đối với nhiều đối tượng là khả năng lặp qua các phần tử.

Câu trả lời thực sự là tất nhiên, tạo ra một trường hợp kiểm tra và đo lường.

+3

C++ mảng được đặt ra trong bộ nhớ chính xác như mảng C. Một mảng C++ chỉ là một cấu trúc với một thành viên mảng C duy nhất. – fredoverflow

+0

Tôi chưa bao giờ đo được điều này, nhưng một vector STL sẽ cung cấp cùng một vùng nhớ đệm như một mảng C nếu được sử dụng trong cùng một kiểu (ví dụ: chỉ định số nguyên tố ở init và không phân bổ lại bộ nhớ bằng cách qua 'giới hạn'). – riviera

+0

Bạn biết đấy - đó là sự thật về mặt kỹ thuật. Vì vậy, có lẽ tôi đã được disingenuous. Tuy nhiên, hậu quả hợp lý của việc sử dụng các lớp chung hơn là các kiểu gốc thô không dẫn đến việc sử dụng con trỏ thông minh và các đối tượng bao bọc khác không thể tránh khỏi. –

5

MVC++ 2010 tạo chính xác cùng một mã để đọc/ghi từ hai cấu trúc POD như trong ví dụ của bạn. Vì các offset để đọc/ghi được tính toán tại thời gian biên dịch, điều này không đáng ngạc nhiên. Cùng đi cho xây dựng và tiêu hủy.

Đối với hiệu suất thực tế, quy tắc chung áp dụng: hồ sơ nếu điều đó quan trọng, nếu không - tại sao lại quan tâm?

Lập chỉ mục vào một thành viên mảng có lẽ là một công việc nhiều hơn một chút cho người dùng cấu trúc của bạn, nhưng sau đó một lần nữa, anh ta có thể lặp lại dễ dàng hơn các phần tử.

+0

Phát hiện rất thú vị, cảm ơn bạn đã báo cáo điều này! (Tôi đang sử dụng VS2010: P) – stepelu

2

Trong trường hợp bạn không thể quyết định và muốn giữ lại lựa chọn của bạn đang mở, bạn có thể sử dụng một công đoàn vô danh:

struct Foo 
{ 
    union 
    { 
     struct 
     { 
      double x; 
      double y; 
      double z; 
     } xyz; 
     double arr[3]; 
    }; 
}; 

int main() 
{ 
    Foo a; 
    a.xyz.x = 42; 
    std::cout << a.arr[0] << std::endl; 
} 

Một số trình biên dịch cũng hỗ trợ cấu trúc mang tính chất trong trường hợp đó bạn có thể để phần xyz ra .

+0

Mặc dù không chuẩn, hỗ trợ cho các công đoàn ẩn danh là khá phổ biến: cả GCC và MSVC đều hỗ trợ chúng. Các công đoàn ẩn danh cũng đã được thêm vào tiêu chuẩn ngôn ngữ C1X sắp tới, mặc dù đó là một chặng đường dài bị tiêu chuẩn hóa và thực hiện (heck, hỗ trợ C99 là khá thảm hại như vậy, và tiêu chuẩn đó đã 12 tuổi rồi!). –

+0

@Adam Rosenfield: Công đoàn ẩn danh là tiêu chuẩn trong C++, xem 9.5.4 – Oystein

+0

Tôi có nghĩa là 9.5.2, xin lỗi. – Oystein

1

Sự khác biệt có thể là lưu trữ các biến trong bộ nhớ. Trong trình biên dịch ví dụ đầu tiên có thể thêm phần đệm để căn chỉnh dữ liệu. Nhưng trong trường hợp paticular của bạn nó không quan trọng.

Các vấn đề liên quan