2015-05-28 19 views
6

Trong đoạn mã bên dưới, tôi có một câu lệnh trong khi được sử dụng để đảm bảo chuỗi đầu vào nhỏ hơn 10 ký tự. Tôi đã khai báo số bool được gọi là cont mà tôi sử dụng để báo cho vòng lặp while dừng lại sau khi các điều kiện của tôi đã được đáp ứng.Sử dụng dấu ngoặc nhọn để tách riêng biến mà tôi muốn sử dụng nhiều lần trong C++

#include "stdafx.h" 
#include <iostream> 
#include <string> 

int main() 
{ 
    using namespace std; 

    cout << "Enter a string less than 10 characters long: "; 

    string teststring; 

    { 
     bool cont(false); 

     //if input is 10 or more characters, ask for input again until it is less 
     while (!cont) 
     { 
      getline(cin, teststring); 

      if (teststring.length() >= 10) 
      { 
       cout << "Too long, try again: "; 
      } 
      else 
      { 
       cout << "Thank you.\n\n"; 
       cont = true; 
      } 

     } 
    } 

    return 0; 
} 

Như bạn thấy đó, tôi đã sử dụng một bộ {} s để tách mã ra, đưa ra các biến cont một phạm vi địa phương trong những niềng răng. Tôi đã làm điều này để nếu tôi muốn sử dụng tên biến đó một lần nữa, tôi chỉ có thể tái tuyên bố nó, và khi tôi hoàn thành nó, nó bị phá hủy.

Đây có phải là phương pháp được chấp nhận không? Hay là có cách nào tốt hơn để làm những gì tôi đã làm? Tôi thừa nhận rằng trong kịch bản cơ bản, cụ thể này, điều kiện đơn giản là nó hầu như không cần thiết, nhưng tôi có thể muốn làm điều này cho các vòng lặp phức tạp hơn trong tương lai.

+0

Tại sao bạn sẽ muốn tái khai báo nó nếu bạn đang sử dụng nó một lần nữa? Bạn chỉ có thể đặt nó sai sau vòng lặp và tái sử dụng nếu bạn muốn (không có phạm vi điều chỉnh) – moffeltje

+0

Nếu bạn thấy mình cần làm điều này, bạn có quá nhiều mã trong một hàm. Bạn nên chia ra thành một hàm riêng biệt. –

+0

Câu hỏi tương tự http://stackoverflow.com/questions/21278015/on-using-several-scoped-blocks-in-a-c-function. – AldurDisciple

Trả lời

1

Đây là trường hợp đồ chơi rõ ràng nhưng đây là một thực hành tốt và các khối 'độc lập' có sẵn cho mục đích đó. Tôi tin rằng chúng là một cách tốt hơn để cấu trúc các chức năng dài hơn là chia nhỏ thành các thành viên (trong nhiều trường hợp) không có mục đích riêng biệt.

Trong trường hợp này, bạn có thể cung cấp chương trình nhanh hơn, rõ ràng hơn, an toàn hơn, đặc biệt nếu có nhận xét (có thể một dòng) giới thiệu từng khối.

Tuy nhiên trong trường hợp này, bạn có thể xem xét:

for (bool cont(false);!cont;) 

Trong đó có tác dụng tương tự. Các biến được khai báo trong câu lệnh for(.;.;.) được giới hạn trong phạm vi của tuyên bố đó.

Trong trường hợp này bạn có thể né tránh toàn bộ biến với:

for(;;) //<--- Canonical formulation for 'infinite' loop. 
    { 
     getline(cin, teststring); 

     if (teststring.length() >= 10) 
     { 
      cout << "Too long, try again: "; 
     } 
     else 
     { 
      cout << "Thank you.\n\n"; 
      break; //<--- Escapes the loop. 
     } 

    } 

Footnote (để đáp ứng với ý kiến):

Bạn nên coi một vòng lặp for là 'cú pháp đường' trên một vòng lặp while. Đó là không có khác nhau trong hiệu suất của họ, vv và chỉ cần chọn một trong đó đọc tốt nhất. for(;cond;) trông có vẻ buồn cười.

Có thể có một lợi ích hiệu suất nhỏ (nhỏ) đến break nhưng tôi nghĩ nó thực sự đơn giản và dễ đọc hơn trong nhiều trường hợp.

Nếu mã là phức tạp hơn có thể có thêm 'kết thúc vòng lặp' code để nó trở thành:

for(bool cont(false);!cont;) { 

    //Complex code with multiple 'exit' conditions... 

    if(!cont) { 
     //Go round again code that won't fit nicely in last term of for loop... 
    } 
} 

Trong khi sử dụng break chỉ làm cho một 'thoát nhanh chóng' dễ hiểu hơn. Họ không (rộng rãi) được coi là 'nghiệp xấu' của goto vì họ 'đi đến' một điểm thực hiện rất rõ ràng.

+0

Thật tuyệt vời. Vì vậy, mặc dù không có điều kiện, câu lệnh 'else' sẽ phá vỡ vòng lặp anyways. Đó là điều tuyệt vời cho những thứ cơ bản. Có điều gì sai trái khi chỉ khai báo 'bool' trong điều kiện vòng lặp while? Có một lợi thế cụ thể cho một vòng lặp trong một thời gian? Tôi là một người mới bắt đầu, vì vậy tôi chỉ muốn hiểu đầy đủ nó. Tôi có thể có một kịch bản mà nhiều điều kiện sẽ kết thúc vòng lặp, và 'bool' có vẻ đẹp hơn về mặt thẩm mỹ đối với tôi. –

+0

Tôi thích điều này một chút công bằng. Đối với các vòng lặp có nhiều chức năng hơn, và tùy chọn chỉ phá vỡ hoặc có nhiều điều kiện hoàn thành là rất tốt là tốt. Cảm ơn! –

2

Nói chung? Vâng. Điều này là tốt.

Trong trường hợp cụ thể này? Không cần thiết. Bạn đang không sử dụng lại tên đó và trong mã đơn giản này mà bạn sẽ không sử dụng. Vì vậy, nó chỉ là tiếng ồn.

Xem & hellip; đó là một sự cân bằng.

Tôi thấy mình làm điều này khá một chút trong các hàm thực thi một số câu lệnh SQL có liên quan. Mỗi lần tôi có thể xây dựng nó với một số std::stringstream được gọi là ss. Chắc chắn, tôi có thể cung cấp cho mỗi một tên khác nhau, nhưng nó hoàn toàn ngăn ngừa các lỗi để giữ cho mỗi người xây dựng câu lệnh trong phạm vi riêng của nó.

Nó cũng là một kỹ thuật rất phổ biến khi bạn sử dụng những thứ như bảo vệ khóa.

+0

"Tôi thừa nhận rằng trong kịch bản cơ bản cụ thể này, điều kiện đủ đơn giản là nó hầu như không cần thiết, nhưng tôi có thể muốn làm điều này cho các vòng lặp phức tạp hơn trong tương lai." –

+0

Đồng ý rằng nó là vô nghĩa trong kịch bản này. Tôi đoán ý tôi là nếu tôi có nhiều vòng lặp, mỗi vòng lặp lại làm một điều khác nhau, vì vậy tôi không thể chỉ làm một chức năng trung lập. Nhưng ai đó đã đề cập rằng tôi chỉ có thể tuyên bố 'bool' bên trong điều kiện, điều này có thể có ý nghĩa hơn nhiều. Cảm ơn mặc dù! –

2

Đây là phương pháp được chấp nhận và thực hiện chính xác những gì bạn nói. Tuy nhiên nó hiếm khi được sử dụng vì trong các hàm nhỏ, nó rõ ràng và do đó có thể chấp nhận được biến số cont trong phạm vi cấp cao nhất của hàm. Nếu bạn cảm thấy bạn cần phải tách biệt phạm vi trong một hàm lớn hơn, việc tạo một hàm khác với tên rõ ràng thường được ưu tiên.

Bạn có thể nghĩ rằng các dấu ngoặc nhọn đó là các hàm không tên chỉ được gọi một lần. Nếu bạn thấy mình sử dụng nó rất nhiều, có lẽ bạn nên đặt tên cho nó.

lựa chọn khác là để viết lại các vòng lặp không cần biến cont, ví dụ:

string teststring; 
do 
{ 
    cout << "Enter a string less than 10 characters long: "; 
    getline(cin, teststring); 
} while (teststring.length() >= 10); 

cout << "Thank you.\n\n"; 

Nhưng điều này không phải lúc nào cũng có thể, đặc biệt là nếu bạn cần phải ra một thông điệp khác nhau tùy thuộc vào điều kiện dừng.

2

Vâng, nếu bạn có lý do chính đáng để sử dụng lại biến số thì tốt. Khóa bảo vệ là cách sử dụng phổ biến nhất trong mã của riêng tôi và ví dụ được đưa ra trong câu trả lời của Lightness là std::stringstream ss. Về cơ bản làm điều này bất cứ lúc nào mà chọn một tên biến khác nhau cảm thấy khó xử hơn. Ví dụ. nếu bạn đang viết lock1, lock2, lock3, ... trong mã của bạn.

Tuy nhiên, thực hành được chấp nhận nhiều hơn, sẽ là để coi các thân chức năng dài như là một mùi mã, và tái cấu trúc chúng thành các hàm riêng của chúng. Ví dụ.

... 
string teststring; 

{ 
    bool cont(false); 
    //10 lines of code to handle the foo scenario 
} 
{ 
    bool cont(false); 
    //15 lines of code to handle the bar scenario 
} 
... 

này là tốt hơn xử lý bởi refactoring để trông giống như:

... 
string teststring; 
foo(teststring); 
bar(teststring); 
... 

void foo(string &teststring){ 
bool cont(false); 
//10 lines of code 
} 

void bar(string &teststring){ 
bool cont(false); 
//15 lines of code 
} 
+1

Được tăng hạng cho điểm 'std :: lock_guard'. Ý tưởng rằng tất cả các phần quan trọng nên được tách ra khỏi nhà 'tự nhiên' của họ ở giữa một chức năng trong một chức năng riêng biệt là điên rồ. – Persixty

+1

Điều đó nói rằng tôi có thể đề nghị void foo (string & teststring)? Nếu không, bạn giới thiệu các thời gian có thể là không phù hợp (nếu chuỗi lớn). – Persixty

+1

@DanAllen Tôi đã cố gắng để giữ cho nó đơn giản (xem mục 41 trong hiệu quả hiện đại C + + cho sự phức tạp đầy đủ!) ... nhưng chỉ cần nhìn vào mã OPs và ông đang sửa đổi 'teststring' vì vậy, có, họ chắc chắn nên đã là tài liệu tham khảo! Cảm ơn :-) –

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