2010-09-13 31 views

Trả lời

23

Trong C++, bạn nên sử dụng tiêu chuẩn :: sao chép theo mặc định trừ khi bạn có lý do chính đáng để làm khác. Lý do là các lớp C++ xác định ngữ nghĩa bản sao của riêng chúng thông qua hàm tạo bản sao và toán tử gán bản sao và các hoạt động được liệt kê, chỉ std :: copy tôn trọng các quy ước đó.

memcpy() sử dụng dữ liệu thô, byte-khôn ngoan (mặc dù có khả năng được tối ưu hóa nhiều cho kích thước đường bộ nhớ cache, v.v.) và bỏ qua ngữ nghĩa sao chép C++ (đó là hàm C, sau khi tất cả ...).

cblas_dcopy() là một hàm chuyên dùng để sử dụng trong các thường trình đại số tuyến tính sử dụng các giá trị dấu phẩy động chính xác kép. Nó có khả năng vượt trội ở đó, nhưng không nên được coi là mục đích chung.

Nếu dữ liệu của bạn là dữ liệu cấu trúc kiểu POD "đơn giản" hoặc dữ liệu kiểu cơ bản thô, memcpy có thể sẽ nhanh như bạn có thể nhận được. Cũng giống như khả năng, std :: copy sẽ được tối ưu hóa để sử dụng memcpy trong những tình huống này, vì vậy bạn sẽ không bao giờ biết sự khác biệt.

Tóm lại, sử dụng std :: copy().

+0

Có vẻ như 'std :: copy' thay vì sử dụng' std :: memmove' vì phạm vi được phép chồng chéo (ở một đầu). – visitor

+0

@visitor: Có thể là sự thật. Nhưng tôi đặt cược memmove() gọi memcpy() nếu nó xác định phạm vi không chồng chéo (số học con trỏ dễ dàng). –

+0

Tôi đã thấy một triển khai memmove mà chỉ cần làm sao chép ngược nếu chồng chéo sẽ gây ra vấn đề về phía trước. – doron

0

Trong hầu hết các trường hợp, memcpy sẽ là nhanh nhất, vì nó là cấp thấp nhất và có thể được triển khai trong mã máy trên một nền tảng nhất định. (tuy nhiên, nếu mảng của bạn chứa các đối tượng không tầm thường thì memcpy có thể không thực hiện đúng suy nghĩ, vì vậy có thể an toàn hơn khi gắn với std :: copy)

Tuy nhiên, tất cả đều phụ thuộc vào cách stdlib được cấy vào nền tảng vv Vì tiêu chuẩn không nói hoạt động nhanh như thế nào, nên không có cách nào để biết trong “xách tay” vì điều sẽ nhanh nhất.

Việc lập hồ sơ ứng dụng của bạn sẽ hiển thị quảng cáo trên một nền tảng nhất định, nhưng sẽ chỉ cho bạn biết về nền tảng thử nghiệm.

Tuy nhiên, khi bạn lập hồ sơ ứng dụng, bạn rất có thể sẽ thấy rằng các vấn đề nằm trong thiết kế của bạn hơn là chọn phương pháp sao chép mảng. (Ví dụ: tại sao bạn cần sao chép các mảng lớn sao cho phù hợp?)

0

Chỉ cần hồ sơ ứng dụng của bạn. Bạn có thể thấy rằng sao chép không phải là phần chậm nhất của nó.

0

memcpy, tuy nhiên, nếu mảng của bạn chứa các đối tượng không tầm thường, hãy gắn với std :: copy.

+3

Việc triển khai tốt 'std :: copy' thậm chí có thể nhanh hơn cho các đối tượng cơ bản; 'memcpy' phải xử lý các sắp xếp địa chỉ tùy ý, nhưng' std :: copy' biết sự liên kết tại thời gian biên dịch. –

+4

Rất nhiều lời khuyên về hiệu suất C++ dường như bao gồm các vòng loại như "triển khai tốt ... có thể nhanh hơn". Có bao nhiêu trong số những tối ưu hóa giả định này đã thực sự được triển khai, ở bất cứ đâu, bao giờ? – Porculus

+0

@Mike Seymour; Bạn nhận ra rằng đang nói về việc sao chép một mảng, tức là một khối liên tục của bộ nhớ, chứa các đối tượng? –

0

Tôi phải nghĩ rằng những người khác sẽ gọi memcpy(). Có nói rằng tôi không thể tin rằng sẽ có bất kỳ sự khác biệt đáng kể.

Nếu nó thực sự quan trọng đối với bạn, hãy mã hóa cả ba và chạy một trình lược tả, nhưng có thể tốt hơn nếu xem xét những thứ như khả năng đọc/bảo trì, ngoại lệ an toàn, v.v ...(và mã một bộ lắp ráp chèn trong khi bạn đang ở đó, không phải là bạn có khả năng thấy sự khác biệt)

Chương trình của bạn có được luồng không?

Và quan trọng nhất, bạn đang giảm mảng của mình như thế nào? (nó là một mảng) và nó lớn bao nhiêu?

0

memcpy có lẽ là cách nhanh nhất để sao chép một khối bộ nhớ liền kề. Điều này là bởi vì nó có khả năng sẽ được tối ưu hóa cao cho bit cụ thể của phần cứng của bạn. Nó thường được thực hiện như một hàm biên dịch dựng sẵn.

Có nói rằng, và không POD C + + đối tượng là không thể tiếp giáp và do đó sao chép mảng của C + + đối tượng sử dụng memcpy có khả năng cung cấp cho bạn kết quả bất ngờ. Khi sao chép mảng (hoặc bộ sưu tập) của đối tượng C++, std::copy sẽ sử dụng ngữ nghĩa bản sao của đối tượng và do đó phù hợp để sử dụng với các đối tượng không phải POD C++.

cblas_dcopy trông giống như một bản sao để sử dụng với một thư viện cụ thể và có thể có ít sử dụng khi không sử dụng thư viện đó.

+0

tại sao bạn giả sử 'std :: copy' chậm hơn' memcpy'? – jalf

1

Sử dụng tiêu chuẩn :: sao chép trừ khi tiểu sử hiển thị cho bạn lợi ích cần thiết khi thực hiện khác. Nó tôn vinh việc đóng gói đối tượng C++, gọi các hàm tạo bản sao và các toán tử gán, và việc triển khai có thể bao gồm các tối ưu hóa nội tuyến khác như tránh một cuộc gọi hàm ngoài dòng lệnh memcpy() nếu kích thước được biết tại thời gian biên dịch và quá nhỏ biện minh cho phí gọi hàm. (Một số hệ thống có thể có macro memcpy tạo ra các xác định tương tự, nhưng nói chung trình biên dịch C++ sẽ có cái nhìn sâu hơn về những gì tối ưu hóa là tương đương về chức năng.)

FWIW/trên hộp Linux cũ tôi có ích, GCC không làm bất kỳ tối ưu hóa ngoạn mục nào, nhưng bit/type_traits.h không cho phép chương trình dễ dàng xác định xem std :: copy có rơi vào memcpy():

* Copyright (c) 1997 
* Silicon Graphics Computer Systems, Inc. 
* 
* Permission to use, copy, modify, distribute and sell this software 
* and its documentation for any purpose is hereby granted without fee, 
* provided that the above copyright notice appear in all copies and    
* that both that copyright notice and this permission notice appear    
* in supporting documentation. Silicon Graphics makes no      
* representations about the suitability of this software for any    
* purpose. It is provided "as is" without express or implied warranty.   
...                    

/*                    
This header file provides a framework for allowing compile time dispatch   
based on type attributes. This is useful when writing template code.    
For example, when making a copy of an array of an unknown type, it helps   
to know if the type has a trivial copy constructor or not, to help decide  
if a memcpy can be used. 

The class template __type_traits provides a series of typedefs each of 
which is either __true_type or __false_type. The argument to 
__type_traits can be any type. The typedefs within this template will 
attain their correct values by one of these means: 
    1. The general instantiation contain conservative values which work 
     for all types. 
    2. Specializations may be declared to make distinctions between types. 
    3. Some compilers (such as the Silicon Graphics N32 and N64 compilers) 
     will automatically provide the appropriate specializations for all 
     types. 

EXAMPLE: 

//Copy an array of elements which have non-trivial copy constructors 
template <class _Tp> void 
    copy(_Tp* __source,_Tp* __destination,int __n,__false_type); 
//Copy an array of elements which have trivial copy constructors. Use memcpy. 
template <class _Tp> void 
    copy(_Tp* __source,_Tp* __destination,int __n,__true_type); 

//Copy an array of any type by using the most efficient copy mechanism 
template <class _Tp> inline void copy(_Tp* __source,_Tp* __destination,int __n) { 
    copy(__source,__destination,__n, 
     typename __type_traits<_Tp>::has_trivial_copy_constructor()); 
} 
*/ 
Các vấn đề liên quan