|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Jan 2012
Messaggi: 1267
|
[C++] Perchè evitare "goto" a tutti i costi?
Perchè leggo dappertutto che il goto va sempre evitato?
L'unica ragione plausibile è: dato che goto punta ad una parola che non è una variabile, quando il codice diventa lungo si potrebbe per sbaglio chiamare una variabile come l'etichetta del goto. Ad esempio: Codice:
play:
[codice del gioco]
cout << "Play again?"; cin >> again;
if (again == 'y') goto play;
[...tante linee di codice...]
int play;
In realtà, mi rendo conto che saltare fuori da un ciclo può essere pericoloso, ma quando non si è in un ciclo goto mi pare più efficiente (dal punto di vista della quantità di linee di codice richieste) di altri conditional statement. In particolare quando controllo l'input dell'utente: lo si può fare in 3 modi: Codice:
cin >> n; while (condizione su n) cin >> n; Codice:
do {
cin >> n;
} while (condizione su n);
Codice:
input:
cin >> n;
if (condizione su n) goto input
Quindi che ha che non va il goto? Siate convincenti |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Davvero usi i goto?
Scherzi a parte, eccoti una vecchia discussione in cui se ne parlò. Se al termine di quella lettura non ne hai abbastanza, il web è pieno. Un rant contro il GOTO che fa parte della "letteratura" è quello famosissimo di Dijkstra (cerca qualcosa tipo "goto considererd harmful", o roba del genere)
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
#3 |
|
Moderatore
Iscritto dal: Nov 2006
Messaggi: 22068
|
perchè fortunatamente il c++ include tutta una serie di istruzioni, che rendono l'uso del goto non necessario semplificando di molto la chiarezza del codice e il debug
personalmente trovo il goto assolutamente inutile e "pericoloso"con tutti i linguaggi di alto livello
__________________
"WS" (p280,cx750m,4790k+212evo,z97pro,4x8GB ddr3 1600c11,GTX760-DC2OC,MZ-7TE500, WD20EFRX) Desktop (three hundred,650gq,3800x+nh-u14s ,x570 arous elite,2x16GB ddr4 3200c16, rx5600xt pulse P5 1TB)+NB: Lenovo p53 i7-9750H,64GB DDR4,2x1TB SSD, T1000 |
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Jan 2012
Messaggi: 1267
|
Ho dato un'occhio al vecchio topic sul goto che però è da subito stato oggetto di discussioni "di alto livello", fuori dalla mia completa comprensione (ad esempio non ho ancora studiato le eccezioni).
L'idea che mi sono fatto è...la stessa che avevo prima: eviterò di inserire goto in cicli eccetera, ma nel mio giochino memory lo tengo implementato per giocare ancora: label e goto sono all'esterno di tutto il codice, non c'è alcun rischio di saltare fuori da cicli che incasinano il valore di iteratori o altro, e mi risparmio di indentare quello che è il corpo principale del programma il che, oltre ad essere più leggibile, lo trovo anche più logico. Torvalds sarà un cazzaro, oppure no, non so, però quello che ha scritto mi pare ragionevole: "gotos are fine in the case that the code is not naturally indented". Cercherò di limitarmi, ragionandoci bene ogni volta, piuttosto che mettere automaticamente un while o altro. Perlomeno fino a quando non cambierò idea
|
|
|
|
|
|
#5 | |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Comunque GOTO IS EVIL
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
|
#6 |
|
Senior Member
Iscritto dal: Jan 2012
Messaggi: 1267
|
|
|
|
|
|
|
#7 |
|
Senior Member
Iscritto dal: May 2001
Messaggi: 12966
|
L'unica ragione per cui sarebbe utile, e forse anche consigliato usare goto, è in linguaggi come C, in cui magari ti trovi di fronte a gestire una situazione di errore e devi fare un cleanup di alcune aree di memoria in diversi punti del codice dove può accadere l'errore.
In questo caso può essere utile usare goto, per non replicare il codice che gestisce l'errore (e quindi rischiare di introdurne altri), ed evitare di introdurre gli overhead dovuti ad una eventuale chiamata a funzione (anche se con le funzioni inline l'overhead viene annullato, ma comunque dovresti creare una funzione di cleanup per ciascuna funzione che fa allocazioni e quant'altro, diventerebbe complicato). In C++ con la gestione delle eccezioni non dovrebbe essere necessario. In tutti gli altri casi non c'è alcuna ragione per cui usare goto, che ti fa perdere il flusso logico del codice. A livello puramente teorico, l'ideale sarebbe avere un codice senza alcun salto. Ultima modifica di WarDuck : 26-01-2012 alle 11:22. |
|
|
|
|
|
#8 | |
|
Moderatore
Iscritto dal: Nov 2006
Messaggi: 22068
|
Quote:
modifica il tuo memory in maniera da non usare goto e vedrai che il codice sarà sicuramente più comprensibile e di migliore qualità giusto per capire, dove lo trovi così indispensabile il goto nel tuo programma? trovo towalds un "pazzo visionario" sicuramente un genio ma di solito quello che funziona per un genio (o comunque una persona parecchio skillata) non sempre è sinonimo di buone regole anche per chi inizia. es. io uso tantissimo il ? per avere un codice più compatto ma non lo consiglio minimamente ad un principiante.
__________________
"WS" (p280,cx750m,4790k+212evo,z97pro,4x8GB ddr3 1600c11,GTX760-DC2OC,MZ-7TE500, WD20EFRX) Desktop (three hundred,650gq,3800x+nh-u14s ,x570 arous elite,2x16GB ddr4 3200c16, rx5600xt pulse P5 1TB)+NB: Lenovo p53 i7-9750H,64GB DDR4,2x1TB SSD, T1000 Ultima modifica di !fazz : 26-01-2012 alle 11:18. |
|
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Aug 2003
Città: Barletta (BA)
Messaggi: 939
|
Come dannoso?
Ma se l'hanno aggiunto in PHP 5.3 per modernizzare il linguaggio http://php.net/manual/en/control-structures.goto.php
__________________
In a world without fences, who needs Gates? Power by: Fedora 8 - Mac OS X 10.4.11 Ultima modifica di nico159 : 26-01-2012 alle 11:22. |
|
|
|
|
|
#10 | |
|
Senior Member
Iscritto dal: Feb 2006
Messaggi: 1304
|
Quote:
goto non lo uso perchè non serve se si programma OOP... uso la necessità del goto proprio come un campanello d'allarme: ogni funzione dovrebbe svolgere un preciso compito, ma se serve un goto la mia funzione ne sta svolgendo più di uno. Basta spostare ogni "feature" nella sua funzione e magicamente il goto non serve più Si, questo spawna un bel pò di funzioni da 4 o 5 righe, ma trovo che sia meglio da tutti i punti di vista. Ultima modifica di Tommo : 26-01-2012 alle 11:32. |
|
|
|
|
|
|
#11 | ||
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Quote:
Comunque il goto è talmente bello come costrutto sintattico, che ci sono linguaggi che nemmeno lo prevedono. Quote:
Chissà cosa ne pensa Guido...
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
||
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Jan 2012
Messaggi: 1267
|
Visto che ci tenete, vi posto il codice sorgente del mio gioco, ma promettete di non usarlo per arricchirvi
![]() Vi evidenzio in rosso il primo punto dove lo uso, ed in blu il secondo, così non dovete spippettarvelo tutto: Codice:
#include "Classes.h"
#include <iostream>
#include <string>
using namespace std;
bool IsInputInteger(string& line);
int main()
{
string control;
int difficulty;
char again;
string go;
int n, m;
Memory* myGrid;
cout << "Exercise 5.1: have a game at Memory!\n" << endl;
play:
cout << "Select the difficulty:" << endl;
cout << "1) Easy" << endl;
cout << "2) Medium" << endl;
cout << "3) Hard" << endl;
cout << "4) Custom: choose the grid dimension yourself (max 10x10)" << endl;
cin >> control;
while (!IsInputInteger(control)) {
cout << "You should enter a number between 1 and 4..." << endl;
cout << "1) Easy" << endl;
cout << "2) Medium" << endl;
cout << "3) Hard" << endl;
cout << "4) Custom: choose the grid dimension yourself (max 10x10)" << endl;
cin >> control;
}
difficulty = atoi(control.c_str());
switch (difficulty) {
case 1:
n = 4;
m = 4;
break;
case 2:
n = 6;
m = 6;
break;
case 3:
n = 8;
m = 8;
break;
case 4:
do {
cout << "Enter the number of rows and columns of the grid (at least one of two numbers must be an even):" << endl;
cout << "Rows = "; cin >> n; cout << "Columns = "; cin >> m; cout << endl << endl;
} while (n % 2 != 0 && m % 2 != 0);
break;
default:
cout << "If entering a number between 1 and 4 is so hard for you, this game might not be your cup of tea." << endl << endl;
return 0;
}
// Initialize and display the scrambled grid
myGrid = new Memory(n, m);
// myGrid -> SetGrid(n, m);
cout << "This is the scrambled grid: memorize it" << endl;
myGrid -> OrderedGrid();
myGrid -> ScrambleGrid();
myGrid -> PrintGrid(cout, myGrid);
cout << endl << "Type GO! when you're ready to start playing: ";
do {cin >> go;} while (go != "GO!");
system("cls");
// Start solving the grid
string c;
int n1, m1, n2, m2;
int realAttempts = 0;
int idealAttempts = (n*m)/2;
do {
cout << "Now enter the indeces of the 2 elements you think form a couple:" << endl;
elements:
cout << "Element 1 - row "; cin >> control;
while (!IsInputInteger(control)) {
cout << "Element 1 - row ";
cin >> control;
}
n1 = atoi(control.c_str());
cout << "Element 1 - column "; cin >> control;
while (!IsInputInteger(control)) {
cout << "Element 1 - column ";
cin >> control;
}
m1 = atoi(control.c_str());
cout << "Element 2 - row "; cin >> control;
while (!IsInputInteger(control)) {
cout << "Element 2 - row ";
cin >> control;
}
n2 = atoi(control.c_str());
cout << "Element 2 - column "; cin >> control;
while (!IsInputInteger(control)) {
cout << "Element 2 - column ";
cin >> control;
}
m2 = atoi(control.c_str());
if (n1 == n2 && m1 == m2) {
cout << "Enter 2 distinct elements!! Dumbass" << endl;
goto elements;
}
myGrid -> GuessCouple(n1, m1, n2, m2, cout);
++realAttempts;
} while (!myGrid -> IsSolved());
cout << "Congratulations, you have solved the grid! Like a boss!" << endl;
cout << "It took you " << realAttempts - idealAttempts << " attempt(s) more than you should have!" << endl << endl;
delete myGrid;
// Option to play again
cout << "Want to play again? (y/n)" << endl;
do {cin >> again;} while (again != 'y' && again != 'n');
if (again == 'y') {
system("cls");
goto play;
}
return 0;
}
bool IsInputInteger(string& line)
{
for (int i = 0; i < line.size(); ++i) {
if (!isdigit(line[i])) return false;
}
return true;
}
Codice:
do {gioca} while (again == 'y');
Anche nel secondo caso dovrei usare un Codice:
do {inserisci n1, m1, n2, m2} while (n1 == n2 && m1 == m2);
Codice:
cout << "Inserisci ...";
while (n1 == n2 && m1 == m2) {
cout << "Idiota! Inserisci 2 elementi diversi!!";
cin >> ...;
Il goto mi sembra comunque innocuo oltre che risparmioso, perchè non salto fuori da nessun loop. A voi la palla |
|
|
|
|
|
#13 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Sì, infatti, bisogna un'attimo circostanziare il discorso.
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
#14 |
|
Senior Member
Iscritto dal: Feb 2006
Messaggi: 1304
|
@vendetta: quel codice tutto contenuto nel main è un'ottima prova per il mio discorso, andava spezzato almeno in 4 o 5 funzioni. Lo credo bene che non sai come gestire il flusso senza goto se schiaffi tutto nel main
![]() Ad esempio, da "play:" fino alla fine della logica di gioco doveva stare tutto dentro una funzione play() che viene chiamata in un ciclo. Praticamente ogni corpo di ogni ciclo potevi smembrarlo allo stesso modo. In pratica stai programmando come chi programma assembly ora come ora, riuso del codice = 0. In sostanza goto è male perchè se ti serve goto la struttura del tuo programma è sbagliata. Non è che goto è sbagliato di suo. Ultima modifica di Tommo : 26-01-2012 alle 11:56. |
|
|
|
|
|
#15 | |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Sì quel codice chiama un po' vendetta, anzi... vendettaaaaa! (
Ad esempio, questa duplicazione è un sintomo: Codice:
while (!IsInputInteger(control)) {
cout << "Element 2 - column ";
cin >> control;
}
Quote:
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
|
#16 | |
|
Senior Member
Iscritto dal: Jan 2012
Messaggi: 1267
|
Quote:
Cmq sia, detto alla tua maniera suona già meglio... |
|
|
|
|
|
|
#17 |
|
Senior Member
Iscritto dal: Jul 2005
Città: Bologna
Messaggi: 1130
|
Ogni 'if' è un 'goto'.
(flaming expected in 3..2..1..)
__________________
-> The Motherfucking Manifesto For Programming, Motherfuckers |
|
|
|
|
|
#18 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
A suo tempo se ne era straparlato.
Se vuoi scatenare un flame secondo me devi impegnarti di più, caro il mio guerrafondaio
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
#19 |
|
Senior Member
Iscritto dal: Jan 2012
Messaggi: 1267
|
Cmq in realtà la mia mente è già al lavoro per capire come riutilizzare varie linee di codice, che mi trovo a scrivere ora, in futuro.
L'esempio portato da banryu è palese, e rimanda ad un altro problema che mi son posto qua (se volete darci un'occhio vi ringrazio ): ho tutta l'intenzione di farmi una classe derivata da cin che sappia capire se in input riceve un int, un char o che altro, così da evitarmi 7-8 LOC ogni volta che voglio controllare che un utente digiti un numero se è richiesto un numero, e non un carattere.Per intenderci, sto entrando nell'ottica OOP ma per comodità, e perchè voglio far le cose fatte bene e il più generiche possibili, non sto a creare oggetti o funzioni per ogni programmino didattico che sto facendo |
|
|
|
|
|
#20 | |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Esempio 1: Codice:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
/**
* Input: a JPEG image path and a Rectangle
* Output: a new JPEG file as a subimage of the input specified by the Rectangle.
*
* Testing production of subimages from JPEG files.
*
* @author Francesco Baro
*/
public class Test {
public static void main(String... args) {
String path =
"\"C:/Documents and Settings/Francesco/Documenti/Immagini/" +
"00143_grapeleaf_1280x800.jpg\"";
String msg =
"Devi specifiare 5 argomenti:\n" +
"1) il path di un'immagine JPEG.\n" +
"2) la coordinata X per la porzione di immagine da tagliare.\n" +
"3) la coordinata Y per la porzione di immagine da tagliare.\n" +
"4) la coordinata WIDTH per la porzione di immagine da tagliare.\n" +
"5) la coordinata HEIGHT per la porzione di immagine da tagliare.\n" +
"Ad esempio:\n" +
"java Test " + path + " 0 0 150 200";
// Data input & start processing
new ApplicationImpl()
.withUsageMessage(msg)
.withArguments(args)
.start();
}
// Validation & Execution logic implementation
static class ApplicationImpl extends ConsolleApp {
@Override protected boolean validateArguments() {
return checkArgsCount(5)
&& checkFilePathAt(0)
&& checkIntAt(1)
&& checkIntAt(2)
&& checkIntAt(3)
&& checkIntAt(4);
}
@Override protected void execute() {
final String path = getArg(0);
final int x = Integer.parseInt(getArg(1));
final int y = Integer.parseInt(getArg(2));
final int width = Integer.parseInt(getArg(3));
final int height = Integer.parseInt(getArg(4));
File file = new File(path);
try {
BufferedImage jpeg = ImageIO.read(file);
BufferedImage portion = jpeg.getSubimage(x, y, width, height);
File dest = new File(file.getParentFile(), "sub_" + file.getName());
ImageIO.write(portion, "JPEG", dest);
} catch (IOException ex) {
System.err.println("IO error reading/writing specified image file: " + file);
}
System.out.println("Work on " + path + " done.");
}
}
}
Codice:
/**
* Input: a JPEG image path
* Output: two new JPEG files as a subimages: the left half and the right half
*
* Testing vertical half cut of a JPEG image
*
* @author Francesco Baro
*/
public class TestVerticalHalf {
public static void main(String... args) {
String path =
"\"C:/Documents and Settings/Francesco/Documenti/Immagini/" +
"00143_grapeleaf_1280x800.jpg\"";
String msg =
"Devi specifiare il path di un'immagine JPEG.\n" +
"Ad esempio:\n" +
"java TestVerticalHalf " + path;
// Data input & start processing
new ApplicationImpl()
.withUsageMessage(msg)
.withArguments(args)
.start();
}
// Validation & Execution logic implementation
static class ApplicationImpl extends ConsolleApp {
@Override protected boolean validateArguments() {
return checkArgsCount(1)
&& checkFilePathAt(0);
}
@Override protected void execute() {
final String path = getArg(0);
File file = new File(path);
BufferedImage jpeg = null;
try {
jpeg = ImageIO.read(file);
} catch (IOException ex) {
System.err.println("IO error reading the image file: " + file);
}
BufferedImage left = leftHalf(jpeg);
BufferedImage right = rightHalf(jpeg);
try {
File dest = new File(file.getParentFile(), "left_" + file.getName());
ImageIO.write(left, "JPEG", dest);
dest = new File(file.getParentFile(), "right_" + file.getName());
ImageIO.write(right, "JPEG", dest);
} catch (IOException ex) {
System.err.println("IO error writing image file: " + file);
}
System.out.println("Work on " + path + " done.");
}
}
/**
* Get the left half of the given in-memory buffered image.
* @param image the buffered image
* @return the left half of the image
*/
public static BufferedImage leftHalf(BufferedImage image) {
int w = image.getWidth() / 2;
int h = image.getHeight();
return image.getSubimage(0, 0, w, h);
}
/**
* Get the right half of the given in-memory buffered image.
* @param image the buffered image
* @return the right half of the image
*/
public static BufferedImage rightHalf(BufferedImage image) {
int x = image.getWidth() / 2;
int w = image.getWidth() - x;
int h = image.getHeight();
return image.getSubimage(x, 0, w, h);
}
}
Codice:
/**
* Abstract away consolle arguments validation and execution.
*
* @author Francesco Baro
*/
public abstract class ConsolleApp {
/** The "show usage" message */
private String usageMessage = "";
/** The application runtime arguments */
private String[] args = new String[] {};
//
// ----- Public Interface
//
/**
* Set this application usage message
* @param message the application "show usage" message
*/
final public ConsolleApp withUsageMessage(String message) {
usageMessage = message;
return this;
}
/**
* Set this application arguments
* @param args the application arguments
*/
final public ConsolleApp withArguments(String... args) {
this.args = args;
return this;
}
/**
* Launch this consolle application
*/
final public void start() {
if (validateArguments()) execute();
else System.out.println(usageMessage);
}
/**
* Get the argument at index
* @param index the index of the argument in the argument list
* @return the argument value
*/
final public String getArg(int index) {
return args[index];
}
//
// ----- Helper methods for validation
//
/**
* Validate the number of arguments passed in
* @param count minimum number of arguments required
* @return true on validation, false otherwise
*/
final protected boolean checkArgsCount(int count) {
if (args.length != count) {
String error = "Errato numero di argomenti passati.";
System.out.println(error);
return false;
}
return true;
}
/**
* Verify that the indexed arguments is a valid file path (must exists)
* @param index argument index
* @return true on validation, false otherwise
*/
final protected boolean checkFilePathAt(int index) {
File file = new File(args[index].trim());
if (! file.exists()) {
String error = "args[" + index + "] - file inesistente: " + file;
System.out.println(error);
return false;
}
if (! file.isFile()) {
String error = "args[" + index + "] - percorso non valido: " + file;
System.out.println(error);
return false;
}
return true;
}
/**
* Verify that the indexed arguments is a valid integer
* @param index argument index
* @return true on validation, false otherwise
*/
final protected boolean checkIntAt(int index) {
try {
Integer.parseInt(args[index]);
return true;
} catch (NumberFormatException managed) {
String error = "args[" + index + "] - il valore non è un intero: " + args[index];
System.out.println(error);
return false;
}
}
//
// ----- Abstract part
//
/**
* Validate the arguments passed to this consolle app.
* Implemetors should define validation logic here.
* @return true on correct validation, false otherwise
*/
protected abstract boolean validateArguments();
/**
* Execute this consolle app, called on successfull arguments
* validation. Implementors should define application logic here,
* and could use getArg to access the arguments.
*/
protected abstract void execute();
}
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 04:44.












).








