Từ 1 tới 10 trên tổng số 10 kết quả

Đề tài: [C++] Some C++ tips

  1. #1
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,750

    Mặc định [C++] Some C++ tips

    Tip 1: .h or not .h ?

    Xét <iostream> & <iostream.h>. Khác nhau:
    • Kí pháp .h cho các file header chuẩn đã bị “bỏ rơi” từ hơn 5 năm trước.

    • Về chức năng, <iostream> chứa tập các lớp I/O được mẫu hóa hỗ trợ cả kí tự ANSI & Unicode. Ngược lại <iostream.h> chỉ hỗ trợ các dòng hướng kí tự 8-bit.

    • Đặc tả giao diện iostream của C++ chuẩn đã được thay đổi theo nhiều khía cạnh rất tinh vi. Vì vậy, các giao diện và cách thực thi của <iostream> khác với <iostream.h>.

    • Các thành phần <iostream> được khai báo trong namespace std trong khi các thành phần <iostream.h> là toàn cục.
      Vì vậy, không thể cùng sử dụng cả 2 trong 1 chương trình. Nên sử dụng <iostream>, trừ khi làm việc với các đoạn mã xa xưa chỉ tương thích với <iostream.h>.


    Tip 2: Gán tham chiếu tới Rvalue

    Bản chất của rvalue là 1 biểu thức không thể xuất hiện bên trái của toán tử gán. Vì thế, việc gán tham chiếu tới rvalue cũng có hạn chế: chỉ có thể gán tham chiếu tới rvalue như là tham chiếu tới 1 hằng (const). (Điều này là hiển nhiên để đảm bảo chương trình không thể thay đổi rvalue). Ví dụ:

    PHP Code:
    void f(const int i);
       
    int main()
       {
          
    f(2); /* OK */
       

    Chương trình truyền rvalue 2 làm tham số cho hàm f(). Tại thời điểm chạy, C++ tạo 1 temporary object kiểu int có giá trị = 2 và gán cho tham chiếu i. Temporary object và tham chiếu của nó tồn tại từ thời điểm f() được gọi cho tới khi f() kết thúc. Nếu khai báo tham chiếu i không phải là hằng, hàm f() có thể thay đổi i gây ra những hậu quả không lường trước.

    Tip 3: Biểu thức cách nhau bởi dấu phảy

    Biểu thức cách nhau bởi dấu phảy được thừa kế từ C, nó là 1 biểu thức mẹ chứa 1 vài biểu thức con cách nhau bởi dấu phảy. Trong trường hợp này, giá trị của biểu thức mẹ là giá trị của biểu thức con bên phải nhất. Ví dụ:

    PHP Code:
    int j=10;
       
    int i=0;
       while( ++
    i, --j)
       {
          
    /*..lặp chừng nào j khác 0*/
       

    Tip 4: Gọi hàm trước khi chương trình chạy

    Khi 1 ứng dụng cần gọi hàm trước khi bắt đầu (VD, các hàm polling, billing, and logger), dễ nhất là gọi chúng trong ctor của 1 đối tượng toàn cục, vì các đối tượng này được tạo trước khi chương trình chính chạy. VD:

    PHP Code:
    class Logger
       
    {
       public:
         
    Logger()
         {
             
    activate_log();
         }
       };

       
    Logger log/*đối tượng toàn cục*/

       
    int main()
       {
           
    record prec=read_log();
           
    //.. mã ứng dụng
       


    Tip 5: Tránh sự phức tạp của cú pháp Con trỏ tới hàm:

    Con trỏ tới hàm là 1 trong những cú pháp khó đọc nhất trong C++ (Cú pháp duy nhất khó đọc hơn có lẽ là con trỏ tới thành viên). VD:

    void (*p[10]) (void (*)());

    Ý nghĩa: p là 1 “mảng 10 con trỏ tới hàm kiểu void và có 1 tham số là con trỏ tới hàm khác kiểu void và không có tham số nào”. Cực kì khó đọc!!! Ở đây có thể đơn giản hóa bằng việc sử dụng các typedef. Đầu tiên, khai báo 1 typedef cho “con trỏ tới 1 hàm kiểu void và không có tham số”:

    typedef void (*pfv)();

    Tiếp theo, khai báo 1 typedef cho “con trỏ tới 1 hàm kiểu void và có 1 tham số kiểu pfv”:

    typedef void (*pf_taking_pfv) (pfv);

    bây giờ khai báo mảng 10 con trỏ như vậy:

    pf_taking_pfv p[10]; /*equivalent to
    void (*p[10]) (void (*)()); but much more readable*/


    Tip 6: Con trỏ tới các thành viên

    Có 2 loại con trỏ tới thành viên: con trỏ tới hàm thành viên và con trỏ tới dữ liệu thành viên. Con trỏ tới thành viên là 1 công cụ cực mạnh. Chúng cho phép gọi 1 hàm thành viên của đối tượng mà không cần biết tên hàm - đây là 1 cách thuận tiện để thực hiện các hàm callback. Tương tự, có thể sử dụng con trỏ tới các dữ liệu thành viên để kiểm tra và thay đổi giá trị mà không cần biết tên của nó.

    Con trỏ tới dữ liệu thành viên
    Cú pháp cũng giống như của con trỏ thông thường, chỉ thêm tên lớp theo sau là toán tử :: trước dấu hoa thị. Ví dụ:

    PHP Code:
     int A::*pmi/* pmi là con trỏ t�›i thành viên int của A*/ 
    Khởi tạo con trỏ tới thành viên:

    PHP Code:
    class A
       
    {
       public:
            
    int num;
            
    int x;
       };
       
    int A::*pmi = & A::num/* 1 */ 
    Trong đoạn mã trên, sử dụng pmi và toán tử .* có thể kiểm tra và thay đổi giá trị của num trong bất kì đối tượng nào của lớp A:

    A a1, a2;
    int n=a1.*pmi; /* copy a1.num t�›i n */
    a1.*pmi=5; /* gán giá tr�‹ 5 cho a1.num */
    a2.*pmi=6; /* gán giá tr�‹ 6 cho a2.num */

    Nếu có con trỏ tới A, sử dụng toán tử ->*:

    A * pa=new A;
    int n=pa->*pmi;
    pa->*pmi=5;


    Con trỏ tới hàm thành viên

    Khai báo con trỏ tới hàm thành viên cũng giống con trỏ tới hàm thông thường, ngoại trừ có thêm tên lớp theo sau bởi toán tử ::. VD sau khai báo con trỏ tới 1 hàm của lớp A trả về giá trị int và ko có tham số nào (lưu ý cặp dấu ngoặc đơn là bắt buộc):

    PHP Code:
    class 
       
    {
       public:
            
    int func (); 
       };

       
    int (A::*pmf) (); 
    Gọi hàm thành viên được pmf trỏ tới bằng toán tử .*:

    pmf=&A::func;
    A a;
    (a.*pmf)(); /* gọi a.func() */

    Nếu có con trỏ tới đối tượng, sử dụng toán tử: ->*

    A *pa=&a;
    (pa->*pmf)(); /*gọi pa->func() */

    Con trỏ tới hàm thành viên tôn trọng tính đa hình (nếu gọi 1 hàm thành viên ảo qua con trỏ, lời gọi sẽ được gán kiểu động). Lưu ý là không thể lấy địa chỉ của ctor và dtor

    Tip 7: Tránh phân mảnh bộ nhớ

    Các ứng dụng thường xuyên cấp phát và thu hồi bộ nhớ động sẽ suy giảm hiệu suất thấy rõ nếu chạy trong thời gian dài, thậm chí có thể crash. Lí do là việc lặp đi lặp lại cấp phát và thu hồi bộ nhớ khiến heap bị phân mảnh (đặc biệt nếu cấp phát và thu hồi các khối nhớ nhỏ). Một vùng heap bị phân mảnh có thể có nhiều khối nhớ tự do, nhưng lại nhỏ và không liên tiếp. Ví dụ sau thể hiện vùng heap của hệ thống. 0 thể hiện khối nhớ tự do & 1 thể hiện khối nhớ đang được sử dụng:

    100101010000101010110

    Vùng heap trên sẽ không thể cấp phát 1 khối nhớ có 5 đơn vị mặc dù nó có tổng cộng 12 đơn vị tự do. Vùng heap dưới đây có ít đơn vị tự do hơn lại cấp phát được:

    1111111111000000

    Làm gì để trành phân mảnh heap? Trước tiên, sử dụng bộ nhớ động càng ít càng tốt (có thể sử dụng bộ nhớ tĩnh, tự động, hoặc sử dụng các container STL). Thứ hai, cố gắng cấp phát và thu hồi các khối nhớ càng lớn càng tốt. Cuối cùng, hãy sử dụng 1 vùng nhớ đệm riêng.

    Tip 8: Không lẫn lộn Delete với Delete []

    Các LTV thường cho rằng sẽ OK nếu sử dụng delete thay vì delete [] để giải phóng mảng các kiểu built-in. VD:

    PHP Code:
     int *p=new int[10];
       
    delete p/*sai; nên là: delete[] p*/ 
    Điều này nói chung không đúng. Theo C++ chuẩn, sử dụng delete để giải phóng mảng cấp phát động của bất kì kiểu gì sẽ dẫn đến các hậu quả không lường trước. Thực tế, trên 1 số platform, các ứng dụng sử dụng delete thay vì delete [] mà không bị crash chỉ là do may mắn (!): Visual C++ là 1 VD, nó thực hiện cả delete[] và delete cho các kiểu built-in bằng cách gọi hàm free(). Tuy nhiên, không có gì bảo đảm các phiên bản sắp tới của Visual C++ giữ lại đặc điểm này. Cũng không có bảo đảm rằng điều này là an toàn trên các compiler khác.

    Tip 9: Tối ưu hóa kích thước lớp

    Kích thước 1 lớp có thể thay đổi bằng việc thay đổi trật tự khai báo các thành viên:

    PHP Code:
    struct A
       
    {
           
    bool a;
           
    int b;
           
    bool c;
       }; 
    /*sizeof (A) == 12*/ 
    Trong trường hợp trên, sizeof (A) = 12. Trình biên dịch đã đặt 3 byte đệm (padding bytes) sau mỗi thành viên bool cho “vừa vặn” với biên giới 4-byte (four-byte boundary). Có thể giảm kích thước của A bằng cách tổ chức lại các thành viên của nó như sau:

    PHP Code:
    struct B
       
    {
           
    bool a;
           
    bool c;
           
    int b;
       }; 
    // sizeof (B) == 8 
    Lần này, trình biên dịch chỉ đặt 2 byte đệm sau thành viên c. Vì b chiếm 4 byte, nó cơ bản đã vừa với biên giới 4-byte mà không cần đặt các byte đệm.

    Tip 10: Tránh các Temporary Object

    C++ có thể “đâm sau lưng chiến sĩ” bằng việc tạo các temporary object. Chi phí cho temporary object đôi khi rất lớn vì cả ctor & dtor đều được gọi. VD:

    Complex x, y, z;
    x=y+z; /* tạo temporary object */

    Biểu thức y+z; sẽ tạo 1 temporary object kiểu Complex chứa kết quả của phép cộng. Sau đó gán temporary object này cho x rồi huỷ bỏ nó. Có thể tránh bằng 2 cách:

    PHP Code:
    // 1. khởi tạo thay vì gán
       
    Complex y,z;
       
    Complex x=y+z;

       
    // 2. sử dụng +=
       
    x=y
       
    x+=z

    Tip 11: Khai báo lớp bên trong (nested class) là bạn của lớp chứa

    Hãy đặt khai báo Friend sau khai báo nested class:

    PHP Code:
     class A
       
    {
       private:
           
    int i;

       public:

           class 
    /*nested class được khai báo trư�›c*/
           
    {
            public:
                  
    B(a) { a.i=0;}; /*truy nhập thành phần private của A */
           
    };

           
    friend class B;/*khai báo friend tại đây*/
       
    }; 
    Nếu khai báo Friend trước, compiler sẽ bỏ qua vì vẫn chưa thấy Friend class

    Tip 12: Lưu các đối tượng được cấp phát động trong STL Containers

    Khi cần lưu các đối tượng có kiểu khác nhau trong cùng 1 container, cách thông thường là lưu con trỏ tới các đối tượng được cấp phát động. Tuy nhiên, hãy sử dụng cách sau:

    PHP Code:
    class Base {};
       class 
    Derived : public Base{};

       
    std::vector <Base *> v;
       
    v.push_back(new Derived);
       
    v.push_back(new Base); 

    Cách này đảm bảo rằng các đối tượng được lưu giữ chỉ có thể được truy nhập qua container của chúng. Thực hiện xóa như sau:

    PHP Code:
    delete v[0];
       
    delete v[1]; 
    Tip 13: Sử dụng Vector như 1 mảng

    Nếu cần lấy địa chỉ mảng bên trong của 1 vector v, sử dụng &v[0] hoặc &*v.front(). VD:

    PHP Code:
     void func(const int arr[], size_t length );
       
    int main()
       {
           
    vector <intvi;
           
    //.. fill vi
           
    func(&vi[0], vi.size());
       } 
    Một số chú ý:
    • func() không được truy nhập tới các phần tử quá giới hạn

    • Các phần tử bên trong vector phải liên tiếp. Mặc dù C++ chuẩn không đảm bảo điều này nhưng hầu hết các trình biên dịch vẫn thực hiện. Lỗ hổng này của C++ chuẩn sắp tới cũng sẽ được vá


    Tip 14: Các vector và mảng động nhiều chiều

    Thông thường khai báo và cấp phát mảng nhiều chiều như sau:

    PHP Code:
     int (*ppi) [5]=new int[4][5]; /*đòi hỏi dấu ngoặc đơn*/
       /*fill array..*/
       
    ppi[0][0] = 65;
       
    ppi[0][1] = 66;
       
    ppi[0][2] = 67;
       
    //..
       
    delete [] ppi
    Đây là 1 cách này tẻ nhạt và hay gây lỗi (do phải tự giải phóng vùng nhớ và dễ làm tràn bộ đệm). Thay vì vậy, hãy sử dụng “vector của các vector”:

    PHP Code:
    #include <vector>
       #include <iostream>
       
    using namespace std;
       
    int main()
       {
           
    vector <vector <int> > v/*2 chiều*/
           
    v.push_back(vector <int>()); /*tạo v[0]*/
           
    v.push_back(vector <int>()); /*tạo v[1]*/
           
    v[0].push_back(15); /*gán v[0][0]*/
           
    v[1].push_back(16); /*gán v[1][0]*/
       

    Vì vector chồng toán tử [], có thể sử dụng cú pháp [][] như thường:

    PHP Code:
    cout << v[0][0];
       
    cout << v[1][0]; 
    2 lợi thế chính của “vector của các vector” là tự động cấp phát vùng nhớ khi cần và tự động giải phóng khi sử dụng xong. Do vậy, không lo bị rò rỉ bộ nhớ.

    Tip 15: Không lưu các đối tượng auto_ptr trong STL Container

    Khi gán hay copy 1 auto_ptr này sang 1 auto_ptr khác, quyền sở hữu con trỏ cũng được chuyển giao theo. Vì vậy, con trỏ của auto_ptr nguồn sẽ = null, gây ra những lỗi không lường trước.

    PHP Code:
    std::vector <auto_ptr <Foo> > vf;/*vector các auto_ptr*/
       // ..fill vf
       
    int g()
       {
            
    std::auto_ptr <Footemp=vf[0]; /*vf[0] trở thành null*/
       

    Thậm chí khi 1 đoạn mã không thực hiện tường minh toán tử copy hay gán, nhiều thuật toán (std::swap(), std::random_shuffle() v.v...) cũng tạo ra temporary copy của 1 hay nhiều phần tử và làm chúng = null.

    Các LTV Visual C++ thường cho rằng họ không gặp vấn đề gì khi dùng auto_ptr trong STL container. Điều này là do mã thực thi auto_ptr trong Visual C++ dựa trên 1 đặc tả đã lỗi thời. Một khi M$ quyết định tuân theo chuẩn ANSI/ISO C++ và thay đổi Standard Library thì đoạn mã sử dụng auto_ptr trong STL container sẽ trở nên nguy hiểm. Vì vậy, hãy sử dụng các con trỏ thông thường hay con trỏ thông minh (những lớp như vậy có sẵn ở www.Boost.org) thay cho auto_ptr trong STL container.

    Viết theo tài liệu : The Top 20 C++ Tips of All Time
    http://www.devx.com/cplus/article/16328

    Nguồn tiếng Việt lấy từ diendantinhoc.net
    Email: admin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667 (Office: 04 6329 2380)
    Yahoo & Skype: dreaminess_world (Vui lòng chỉ rõ mục đích ngay khi liên hệ, cảm ơn!)

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó. Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp!

  2. #2
    Ngày gia nhập
    08 2006
    Nơi ở
    TpHCM
    Bài viết
    202

    Tip 2: Gán tham chiếu tới Rvalue
    Bản chất của rvalue là 1 biểu thức không thể xuất hiện bên trái của toán tử gán. Vì thế, việc gán tham chiếu tới rvalue cũng có hạn chế: chỉ có thể gán tham chiếu tới rvalue như là tham chiếu tới 1 hằng (const). (Điều này là hiển nhiên để đảm bảo chương trình không thể thay đổi rvalue)

    ==>điều này là không đúng, khi tham chiếu rvalue hoàn toàn có thể là biến, cái này gọi là alias (bí danh) trong ngôn ngữ lập trình:
    int x =1;
    int&y = x;
    void f(const int & i);
    f(x); //OK

    mình đồng ý với việc sử dụng nhiều STL, thay cho những cái khác

  3. #3
    Ngày gia nhập
    11 2006
    Bài viết
    13

    Trích dẫn Nguyên bản được gửi bởi Dreaminess
    Tip 9: Tối ưu hóa kích thước lớp

    Kích thước 1 lớp có thể thay đổi bằng việc thay đổi trật tự khai báo các thành viên:

    PHP Code:
    struct A
       
    {
           
    bool a;
           
    int b;
           
    bool c;
       }; 
    /*sizeof (A) == 12*/ 
    Trong trường hợp trên, sizeof (A) = 12. Trình biên dịch đã đặt 3 byte đệm (padding bytes) sau mỗi thành viên bool cho “vừa vặn” với biên giới 4-byte (four-byte boundary). Có thể giảm kích thước của A bằng cách tổ chức lại các thành viên của nó như sau:

    PHP Code:
    struct B
       
    {
           
    bool a;
           
    bool c;
           
    int b;
       }; 
    // sizeof (B) == 8 
    Lần này, trình biên dịch chỉ đặt 2 byte đệm sau thành viên c. Vì b chiếm 4 byte, nó cơ bản đã vừa với biên giới 4-byte mà không cần đặt các byte đệm.
    Với ví dụ trên thì em hiểu. Nhưng em thử test bằng cách này ,cho hỏi cách lý giải tại sao lại ra 2 size khác nhau:

    Code:
    struct TEST
    {
    	
    	bool a;
    	bool b;
    	char d[10];
    	int c;
    }; //sizeof(TEST) == 16
    Code:
    struct TEST
    {
    	bool a;
    	int c;
    	bool b;
    	char d[10];
    }; //sizeof(TEST) == 20
    Code:
    struct TEST
    {
    	bool a;
    	bool b;
    	int c;
    	char d[10];
    }; //sizeof(TEST) == 20

  4. #4
    Ngày gia nhập
    09 2006
    Bài viết
    62

    Trích dẫn Nguyên bản được gửi bởi trickyboy
    Với ví dụ trên thì em hiểu. Nhưng em thử test bằng cách này ,cho hỏi cách lý giải tại sao lại ra 2 size khác nhau:

    Code:
    struct TEST
    {
    	
    	bool a;
    	bool b;
    	char d[10];
    	int c;
    }; //sizeof(TEST) == 16
    Code:
    struct TEST
    {
    	bool a;
    	int c;
    	bool b;
    	char d[10];
    }; //sizeof(TEST) == 20
    Code:
    struct TEST
    {
    	bool a;
    	bool b;
    	int c;
    	char d[10];
    }; //sizeof(TEST) == 20
    Và vấn đề là ??
    Click here for more Info of Cviet-Translator-Group

    ! be thankful for small blessings...

  5. #5
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,750

    Cái đầu tiên nhé: 1+1+10+4=16

    Cái thứ 2: 4+4+11=19 , sizeof sẽ là 20

    Cái thứ 3: 4+4+10=18, sizeof sẽ là 20

    Có gì lạ đâu nhỉ?
    Email: admin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667 (Office: 04 6329 2380)
    Yahoo & Skype: dreaminess_world (Vui lòng chỉ rõ mục đích ngay khi liên hệ, cảm ơn!)

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó. Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp!

  6. #6
    Ngày gia nhập
    08 2006
    Nơi ở
    TpHCM
    Bài viết
    202

    Mặc định [C++] Some C++ tips

    cha`,có vẻ bạn vẫn còn mù mờ về Alignment of Structures
    , vấn đề này khá là dễ hiểu, các bạn hãy tìm trong MSDN với từ khóa trên

    Và nhớ là đặc điểm này là Microsoft Specific (có ghi trong MSDN), tức là chỉ có ở Microsoft VC thôi, gcc hay cc thì không còn đúng nữa

  7. #7
    Ngày gia nhập
    08 2006
    Nơi ở
    TpHCM
    Bài viết
    202

    Tip 16: Tại sao cần dùng destructor ảo?
    lười giải thích quá, chỉ cần nhớ là với destructor thì nên luôn dùng kèm với virtual

  8. #8
    Ngày gia nhập
    08 2006
    Nơi ở
    TpHCM
    Bài viết
    202

    Tip 17: Truy suất thuộc tính/ phương thức protected của 1 class có sẵn bằng cách nào?
    đơn giản chỉ cần thừa kế lại class đó, thêm lớp friend nếu cần thiết hoặc viết phương thức public để truy suất

  9. #9
    Ngày gia nhập
    08 2006
    Nơi ở
    TpHCM
    Bài viết
    202

    Tip 18: hôm trước TQN (có lẽ thế) đề cập đến việc thực thi constructor thất bại thì kết quả sẽ ra sao, và anh ta chỉ nói là tùy vào trình biên dịch (có lẽ thế). Cho nên tip này đề cập đến vấn đề làm sao để biết việc thực thi của constructor thất bại?
    đơn giản là sử dụng exception kèm với đoạn code cần kiểm tra (nếu trình dịch hỗ trợ exception) hoặc trả về mã lỗi là biến thành viên của class

    hì hì, chả có gì cao siêu cả.

  10. #10
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,750

    Nhưng mà mấy bài trên của nguyentuan2 đích thị là spam nha
    hì hì, chả có gì cao siêu cả.
    Câu này nghe rất có hứng đó. Đáng được đưa lên trang nhất
    Email: admin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667 (Office: 04 6329 2380)
    Yahoo & Skype: dreaminess_world (Vui lòng chỉ rõ mục đích ngay khi liên hệ, cảm ơn!)

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó. Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp!

Các đề tài tương tự

  1. Halong Bay cruises - Tips and advice
    Gửi bởi vstquanghiep trong diễn đàn Giới thiệu website, sản phẩm của bạn
    Trả lời: 0
    Bài viết cuối: 08-08-2012, 10:56 AM
  2. Top 10 Utilised iPhone Buying Tips - We Couple 16g, 8gb and 4gb Utilised iPhones
    Gửi bởi ozayyysin trong diễn đàn Giới thiệu website, sản phẩm của bạn
    Trả lời: 0
    Bài viết cuối: 25-02-2012, 10:08 PM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn