Những dấu hiệu của sự khởi tạo chữ thập là gì?


84

Hãy xem xét đoạn mã sau:

#include <iostream>
using namespace std;

int main()
{
    int x, y, i;
    cin >> x >> y >> i;
    switch(i) {
        case 1:
            // int r = x + y; -- OK
            int r = 1; // Failed to Compile
            cout << r;
            break;
        case 2:
            r = x - y;
            cout << r;
            break;
    };
}

G ++ phàn nàn crosses initialization of 'int r'. Câu hỏi của tôi là:

  1. crosses initializationgì?
  2. Tại sao bộ khởi tạo đầu tiên x + yvượt qua quá trình biên dịch, nhưng bộ khởi tạo sau không thành công?
  3. Những vấn đề của cái gọi là crosses initializationgì?

Tôi biết tôi nên sử dụng dấu ngoặc để chỉ định phạm vi r, nhưng tôi muốn biết tại sao, ví dụ: tại sao không phải POD không thể được xác định trong câu lệnh chuyển đổi nhiều trường hợp.


1
Sự hiểu biết của tôi, với các câu trả lời bên dưới, cho điểm 3 là lỗi này là một hạn chế quá mức của c ++. Nếu r không được sử dụng sau nhãn, không có tác động (ngay cả khi ví dụ ở đây sử dụng r, nó có thể bị loại bỏ trong trường hợp 2 và trình biên dịch sẽ đưa ra lỗi tương tự). Bằng chứng tốt hơn là nó được phép trong C, và thậm chí trong C11.
calandoa

Câu trả lời:


95

Phiên bản với int r = x + y;cũng sẽ không biên dịch.

Vấn đề là có thể rđến phạm vi mà trình khởi tạo của nó không được thực thi. Mã sẽ biên dịch tốt nếu bạn loại bỏ hoàn toàn bộ khởi tạo (tức là dòng sẽ đọc int r;).

Điều tốt nhất bạn có thể làm là giới hạn phạm vi của biến. Bằng cách đó, bạn sẽ làm hài lòng cả trình biên dịch và người đọc.

switch(i)
{
case 1:
    {
        int r = 1;
        cout << r;
    }
    break;
case 2:
    {
        int r = x - y;
        cout << r;
    }
    break;
};

Tiêu chuẩn cho biết (6,7 / 3):

Có thể chuyển vào một khối, nhưng không phải theo cách bỏ qua khai báo với khởi tạo. Chương trình nhảy từ một điểm mà một biến cục bộ có thời lượng lưu trữ tự động không nằm trong phạm vi đến một điểm mà nó trong phạm vi không được hình thành trừ khi biến có kiểu POD (3.9) và được khai báo mà không có bộ khởi tạo (8.5).


Nhưng G ++ của tôi không cho phép int r = x + y.
Jichao

10
Vâng, g ++ của tôi không. Kiểm tra lại hoặc nâng cấp trình biên dịch.
avakar

cảm ơn, điều đó hữu ích cho tôi. Tôi nghĩ rằng trình biên dịch C thậm chí không cho phép khai báo sau một số mã. Rõ ràng C99 cho phép rằng mặc dù ... stackoverflow.com/questions/7859424/...
m-ric

36

Bạn nên đặt nội dung của casedấu ngoặc vuông để cung cấp cho nó phạm vi, theo cách đó bạn có thể khai báo các biến cục bộ bên trong nó:

switch(i) {
    case 1:
        {
            // int r = x + y; -- OK
            int r = 1; // Failed to Compile
            cout << r;
        }
        break;
    case 2:
        ...
        break;
};

3

Có thể chuyển vào một khối, nhưng không phải theo cách bỏ qua khai báo với khởi tạo. Một chương trình nhảy từ một điểm mà biến cục bộ có thời lượng lưu trữ tự động không nằm trong phạm vi đến một điểm mà nó trong phạm vi không được định hình trừ khi biến có kiểu POD và được khai báo mà không có trình khởi tạo.

[Example: Code:

void f()
{
  // ...
  goto lx;    // ill-formed: jump into scope of `a'
  // ...
 ly:
    X a = 1;
  // ...
 lx:
   goto ly;    // ok, jump implies destructor
 // call for `a' followed by construction
 // again immediately following label ly
}

--end example]

Việc chuyển từ điều kiện của một câu lệnh switch sang một nhãn trường hợp được coi là một bước nhảy về mặt này.


1
Chào mừng bạn đến với Stack Overflow. Bạn nên cung cấp nguồn cho các trích dẫn của mình, đây là C ++ 03: 6.7 / 3. Nó cũng giống như đoạn tôi đã trích dẫn trong câu trả lời của mình.
avakar

0

Tôi khuyên bạn nên quảng cáo rbiến của bạn trước khi switchtuyên bố. Nếu bạn muốn sử dụng một biến trên các casekhối, (hoặc cùng một tên biến nhưng cách sử dụng khác nhau), hãy xác định nó trước câu lệnh switch:

#include <iostream>
using namespace std;

int main()
{
    int x, y, i;
    cin >> x >> y >> i;
// Define the variable before the switch.
    int r;
    switch(i) {
        case 1:
            r = x + y
            cout << r;
            break;
        case 2:
            r = x - y;
            cout << r;
            break;
    };
}

Một trong những lợi ích là trình biên dịch không phải thực hiện phân bổ cục bộ (hay còn gọi là đẩy lên ngăn xếp) trong mỗi casekhối.

Một hạn chế của cách tiếp cận này là khi các trường hợp "rơi" vào các trường hợp khác (tức là không sử dụng break), vì biến sẽ có giá trị trước đó.


2
Tôi sẽ đề nghị làm theo cách khác. Trình biên dịch không phải thực hiện "phân bổ cục bộ" trong cả hai trường hợp (và trong thực tế thì không).
avakar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.