STDIO
Tìm kiếm gần đây
    • Nội dung
    • QR Code
    • 0
    • 0
    • Sao chép

    Tối Ưu Hóa - Tối Ưu Hóa Code C++

    Các mẹo tối ưu hóa code làm tăng hiệu suất trong lập trình C++.
    18/09/2014
    26/09/2020
    4 phút đọc
    Tối Ưu Hóa - Tối Ưu Hóa Code C++

    Các trường hợp tối ưu hóa codes

    • Tạo một đối tượng khi thật sự cần thiết.
    • Gọi hàm khởi tạo khi thật sự cần thiết.
    • Chỉ định hàm khởi tạo cho các đối tượng là thuộc tính của class.
    • Sử dụng tham chiếu, con trỏ (shallow copy) nếu có thể.

    Tạo một đối tượng khi thật sự cần thiết

    Khi thật sự không cần thiết nên hạn chế khởi tạo 1 đối tượng vì chi phí bao gồm hiệu suất cho khởi tạo và thu hồi rất lớn, bên cạnh đó còn tốn bộ nhớ để lưu trữ.

    Xét trường hợp sau

    void BeAStdio()
    {
    	Stdio sObj;
    	
    	...
    }

    Từ đoạn ... trở xuống, không hề sử dụng sObj nên đó là 1 sự lãng phí phải bỏ, tuy nhìn đơn giản nhưng nếu không xóa dòng code đó, khi đến trường hợp code phức tạp hơn như bên dưới:

    char* BeAStdio(bool enable)
    {
    	Stdio sObj;
    	
    	if (enable == true)
    		return nullptr;
    	else
    		...
    }

    Nếu enable == true thì hàm sẽ ngưng thực thi và trả nullptr, sObj sẽ không có chức năng gì trong hàm, trường hợp này rất lãng phí.

    Gọi hàm khởi tạo khi thật sự cần thiết

    Mặc định khởi tạo 1 đối tượng, hàm tạo (constructor) được gọi sau khi hàm đó được khởi tạo, giả sử trong hàm khởi tạo có dạng sau:

    #include <string.h>
    
    typedef char byte;
    
    class Proifle
    {
    private:
    	byte* m_profilePicture;
    	int m_profilePictureLength;
    	
    	char* m_DNAString;
    	int m_DNAStringLength;
    
    public:
    	Profile(int pictureLength, byte* profilePicture,
    				int DNALength, char* DNA)
    	{
    		m_profilePicture = new byte[pictureLength];
    		m_profilePictureLength = new char[DNALength];
    		
    		memcpy(m_profilePicture, profilePicture, pictureLength);
    		memcpy(m_DNAString, DNA, DNALength);
    	}
    };
    
    int main()
    {
    	/*......*/
    
    	StdioMember member(picLength, pic, dnaLength, dna);
    
    	/*......*/
    	
    	return 0;
    }

    Từ lúc khởi tạo StdioMember member thì constructor sẽ gọi ngay sau đó và điều thuận tiện này cũng là điều bất lợi, đôi lúc đó chưa phải là thời điểm muốn khởi tạo các giá trị cho thuộc tính trong đối tượng, có khi thời điểm đó cũng đang cần hiệu suất của máy tính và muốn việc khởi tạo được diễn ra sau đó, không nên đặt các khởi tạo tại constructor.

    Nếu chưa cần khởi tạo, có thể sử dụng con trỏ và khi nào cần khởi tạo sẽ cấp phát động bằng toán tử new.

    Nếu bài toán đặt ra là phải cấp phát đối tượng nhưng chưa cần khởi tạo các giá trị trong đối tượng thì cần thiết kế lại lớp như sau.

    • Thêm 1 constructor với thân của constructor là rỗng.
    • Viết thêm 1 phương thức khởi tạo và gọi phương thức đó khi nào thấy cần thiết.

    Code như sau

    #include <string.h>
    
    typedef char byte;
    
    class Profile
    {
    private:
    	byte* m_profilePicture;
    	int m_profilePictureLength;
    	
    	char* m_DNAString;
    	int m_DNAStringLength;
    
    public:
    	Profile()
    	{
    	}
    	
    	void Init(int pictureLength, byte* profilePicture,
    				int DNALength, char* DNA)
    	{
    		m_profilePicture = new byte[pictureLength];
    		m_profilePictureLength = new char[DNALength];
    		
    		memcpy(m_profilePicture, profilePicture, pictureLength);
    		memcpy(m_DNAString, DNA, DNALength);
    	}
    };
    
    int main()
    {
    	/*......*/
    
    	Profile member;
    
    	/*......*/
    	
    	member.Init();
    	
    	return 0;
    }

    Chỉ định hàm khởi tạo cho các đối tượng là thuộc tính của class

    Với 1 thuộc tính trong 1 class, có thể đó là 1 đối tượng, nếu như khai báo thông thường xem như đã gọi constructor mặc định cho nó và không có cách thức để gọi các constructor mong muốn.

    class Sins
    {
    private:
    	string m_name;
    	
    public:
    	Sins(string & name)
    	{		
    		m_name = name;
    	}
    }

    Phân tích code trên có, 2 quá trình:

    • Sins được tạo ra.
    • Sins gọi constructor.

    Trong quá trình đối tượng Sins được tạo thành thì m_name được tạo, nó sẽ gọi constructor của nó.

    Vào thân hàm constructor của Sins và xảy ra copy-constructor gán name vào m_name.

    Xét riêng m_name thấy nó phải gọi constructor trước, sau đó lại tiến hành gán (gọi copy-construtor) thêm 1 lần nữa. Do đó, nên gọi thẳng copy-constructor để tránh thêm bước gọi constructor.

    Để làm điều này, chỉ định copy-constructor cho Sins khi nó đang khởi tạo bằng cách sau

    class Sins
    {
    private:
    	string m_name;
    	
    public:
    	Sins(string & name):m_name(name)
    	{
    	}
    }

    Sử dụng tham chiếu, con trỏ nếu có thể

    Với C, chỉ có con trỏ, bản chất khi truyền con trỏ vào 1 hàm là gán địa chỉ của con trỏ, nếu con trỏ đang quản lý 1 đối tượng, không tốn kém việc truyền các đối tượng vào hàm. Đối với cách truyền tham chiếu (trong C++) cũng có ý tưởng tương tự như vậy.

    Như hàm vẽ 1 đối tượng tên là Sins bên dưới, không cần thiết phải sao chép cả đối tượng vì trong trường hợp này chỉ muốn lấy dữ liệu từ nó để vẽ (có thể sử dụng phương pháp truyền địa chỉ qua pointer nếu muốn, nhưng ở đây dùng phương pháp tên chung - truyền tham chiếu).

    void DrawSins(const Sins & s, int posX, int posY)
    {
    	Draw(s.texture, s.rect.x, s.rect.y, s.rect.width, s.height, posX, posY);
    }

    Bài chung series

    0 Bình luận
    Modern C++

    Modern C++

    STDIO Training - Đào Tạo Lập Trình C++.

    Đề xuất

    Tối Ưu Hóa - Coding Convention
    Hướng dẫn sử dụng và xây dựng Coding Convention.
    Tối Ưu Mã C/C++ Cho Người Mới Bắt Đầu
    Giới thiệu các phương pháp tối ưu hoá mã nguồn C/C++.
    28/08/2015

    Khám phá

    9 Tính Năng Quan Trọng Trong C++11
    C++11 là một phiên bản cải tiến và nâng cấp từ C++98 (hay các bạn vẫn ...
    13/08/2015
    SEO - Tối Ưu Đường Dẫn Thân Thiện Người Dùng
    Tối ưu hóa đường dẫn mang lại trải nghiệm thân thiện với người dùng và ...
    Tối Ưu Hóa - Quản Lý Bộ Nhớ Nhỏ và Phân Mảnh
    Hướng dẫn tạo hệ thống tự cấp phát và thu hồi bộ nhớ dành cho bộ nhớ nhỏ ...
    Tối Ưu Xử Lý Chuỗi với StringBuilder - Phần 1
    Bài viết giới thiệu và phân tích hiệu năng khi xử lí chuỗi với đối tượng ...
    03/02/2018
    Đồ Hoạ trên Cửa Sổ Dòng Lệnh - Console Graphics
    Các thư viện đồ họa đã phát triển rất mạnh mẽ, tận dụng gần như tối đa ...
    02/10/2014
    OpenCV – Cài Đặt và Ví Dụ Minh Họa Sử Dụng
    Giới thiệu tổng quan OpenCV, hướng dẫn cài đặt và viết chương trình minh ...
    Các Kiến Thức Cần Chuẩn Bị Cho Buổi Phỏng Vấn C++
    Các kiến thức cần chuẩn bị cho buổi phỏng vấn C++ và cho công việc C++.
    Performance của switch-case so với if-else
    So sánh performance giữa switch-case so với if-else và các kĩ thuật tối ...
    Khi bạn nhấn vào liên kết sản phẩm do STDIO đề xuất và mua hàng, STDIO có thể nhận được hoa hồng. Điều này hỗ trợ STDIO tạo thêm nhiều nội dung hữu ích. Tìm hiểu thêm.
    STDIO
    Trang chính
    Công ty TNHH STDIO

    30, Trịnh Đình Thảo, Hòa Thạnh, Tân Phú, Hồ Chí Minh
    +84 28.36205514 - +84 942.111912
    developer@stdio.vn

    383/1 Quang Trung, Phường 10, Quận Gò Vấp, Hồ Chí Minh
    Số giấy phép ĐKKD: 0311563559 do sở Kế hoạch và Đầu Tư TPHCM cấp ngày 23/02/2012

    ©STDIO, 2013 - 2020