PDA

View Full Version : [C++] Perchè evitare "goto" a tutti i costi?


vendettaaaaa
26-01-2012, 09:23
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:
play:
[codice del gioco]
cout << "Play again?"; cin >> again;
if (again == 'y') goto play;
[...tante linee di codice...]
int play;
E' per questo? Altri motivi non me ne vengono.
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:
cin >> n;
while (condizione su n) cin >> n;
do {
cin >> n;
} while (condizione su n);
input:
cin >> n;
if (condizione su n) goto input
Trovo la 3° opzione molto comoda in certi casi, ma mi sono sempre costretto ad usare la 1° per evitare appunto un "bad habit" però raddoppiando il numero di righe dedicate a cout e cin...

Quindi che ha che non va il goto? Siate convincenti :D

banryu79
26-01-2012, 09:32
Davvero usi i goto? :eek: Pussa via! :ciapet:
Scherzi a parte, eccoti una vecchia discussione in cui se ne parlò (http://www.hwupgrade.it/forum/showthread.php?t=1698555).

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)

!fazz
26-01-2012, 09:50
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

vendettaaaaa
26-01-2012, 10:52
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 :read:

banryu79
26-01-2012, 11:05
Cercherò di limitarmi, ragionandoci bene ogni volta, piuttosto che mettere automaticamente un while o altro.
Perlomeno fino a quando non cambierò idea :read:
Ecco bravo, la cosa migliore è fare esperienza diretta, riesaminarla e formarsi una propria circostanziata opinione.
Comunque GOTO IS EVIL :D

vendettaaaaa
26-01-2012, 11:07
Ecco bravo, la cosa migliore è fare esperienza diretta, riesaminarla e formarsi una propria circostanziata opinione.
Comunque GOTO IS EVIL :D
Esatto, devo sbatterci la testa per capire cosa non va nel goto (sempre che ci sia qualcosa :asd: ).

WarDuck
26-01-2012, 11:14
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.

!fazz
26-01-2012, 11:15
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 :read:

prendilo come esercizio

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.

nico159
26-01-2012, 11:19
Come dannoso?

Ma se l'hanno aggiunto in PHP 5.3 per modernizzare il linguaggio
http://php.net/manual/en/control-structures.goto.php
:D

Tommo
26-01-2012, 11:26
es. io uso tantissimo il ? per avere un codice più compatto ma non lo consiglio minimamente ad un principiante.

Un'altro estimatore di ? :D

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ù :D
Si, questo spawna un bel pò di funzioni da 4 o 5 righe, ma trovo che sia meglio da tutti i punti di vista.

cdimauro
26-01-2012, 11:29
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".
Con questo hai appena trasformato il "sarà" in "è". :O

Comunque il goto è talmente bello come costrutto sintattico, che ci sono linguaggi che nemmeno lo prevedono. :D
Come dannoso?

Ma se l'hanno aggiunto in PHP 5.3 per modernizzare il linguaggio
http://php.net/manual/en/control-structures.goto.php
:D
Ma LOL.

Chissà cosa ne pensa Guido... :asd:

vendettaaaaa
26-01-2012, 11:34
Visto che ci tenete, vi posto il codice sorgente del mio gioco, ma promettete di non usarlo per arricchirvi :asd:
Vi evidenzio in rosso il primo punto dove lo uso, ed in blu il secondo, così non dovete spippettarvelo tutto:
#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;
}

Nel caso di play again mi pare totalmente innocuo. Distruggo la matrice memory appena l'utente la risolve, prima del "play again", quindi non c'è rischio di memory leak. Se non usassi goto, dovrei indentare tutto quanto in un
do {gioca} while (again == 'y');
e non mi va di spostare tutto a destra di 4 spazi, non ho uno schermo panoramico!

Anche nel secondo caso dovrei usare un
do {inserisci n1, m1, n2, m2} while (n1 == n2 && m1 == m2);
ma di nuovo, vorrei non indentare troppo. Inoltre, dato che se l'user viola la condizione lo insulto, la seconda volta il messaggio di testo è diverso e per ottenere ciò dovrei usare non più un do while, bensì un while:
cout << "Inserisci ...";
while (n1 == n2 && m1 == m2) {
cout << "Idiota! Inserisci 2 elementi diversi!!";
cin >> ...;
ripetendo ben 2 volte i 4 blocchi di acquisizione di n1, m1, n2 ed m2.
Il goto mi sembra comunque innocuo oltre che risparmioso, perchè non salto fuori da nessun loop.

A voi la palla :D

banryu79
26-01-2012, 11:51
goto non lo uso perchè non serve se si programma OOP...

Sì, infatti, bisogna un'attimo circostanziare il discorso.

Tommo
26-01-2012, 11:54
@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 :asd:

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.

banryu79
26-01-2012, 12:00
Sì quel codice chiama un po' vendetta, anzi... vendettaaaaa! (:D), è in astinenza di refactoring.
Ad esempio, questa duplicazione è un sintomo:
while (!IsInputInteger(control)) {
cout << "Element 2 - column ";
cin >> control;
}



In sostanza goto è male perchè se ti serve goto la struttura del tuo programma è sbagliata. Non è che goto è sbagliato di suo.

Non è sbagliata: è aspaghettata.

vendettaaaaa
26-01-2012, 12:02
@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 :asd:

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.
Essendo un programmino del menga non sono stato a creare una funzione nella classe Memory per ogni "funzione logica" che serve, certo che se faccio myGrid.play() posso tranquillamente metterci un do while!
Cmq sia, detto alla tua maniera suona già meglio...

shinya
26-01-2012, 12:03
Ogni 'if' è un 'goto'.

(flaming expected in 3..2..1..)

banryu79
26-01-2012, 12:06
Ogni 'if' è un 'goto'.

(flaming expected in 3..2..1..)
A suo tempo se ne era straparlato.
Se vuoi scatenare un flame secondo me devi impegnarti di più, caro il mio guerrafondaio :)

vendettaaaaa
26-01-2012, 12:08
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 (http://www.hwupgrade.it/forum/showpost.php?p=36802614&postcount=3) (se volete darci un'occhio vi ringrazio :asd: ): 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 :D

banryu79
26-01-2012, 12:18
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 (http://www.hwupgrade.it/forum/showpost.php?p=36802614&postcount=3) (se volete darci un'occhio vi ringrazio :asd: ): 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 :D
Io ho scritto una fesseria (in Java), per piccolissimi programmini senza interfaccia grafica, che stampano tutto in consolle. Lo scopo era ridurre il codice ridondante da scrivere per la validazione degli argomenti passati da riga di comando e arrivare a scrivere delle robe così:

Esempio 1:

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.");
}
}
}


Esempio 2:

/**
* 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);
}

}


ConsolleApp:

/**
* 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();
}

Se dovesse servirmi tenterei un'approccio del genere anche per l'acquisizione dell'input utente.

Tommo
26-01-2012, 12:27
Essendo un programmino del menga non sono stato a creare una funzione nella classe Memory per ogni "funzione logica" che serve, certo che se faccio myGrid.play() posso tranquillamente metterci un do while!
Cmq sia, detto alla tua maniera suona già meglio...

play() dovrebbe essere chiamata nel do-while, non contenerlo. E' una bella differenza, dato che poi ti serve anche un'altra funzione che contiene il do-while :D
Questo ha l'ovvio vantaggio che puoi chiamare play() come vuoi, non necessariamente causando un do-while, isolando l'idea di "eseguire un solo gioco dall'inizio alla fine".
Noterai che se ci metti il do-while quello che fa la funzione è "eseguire giochi finchè l'utente non ferma" che unisce molta più roba passando da funzione di pura logica di gioco a funzione con input, etc oltre al suo scopo originale di eseguire il gioco.
Modellizza fratello, modellizza! (semicit.)

shinya
26-01-2012, 12:34
A suo tempo se ne era straparlato.
Se vuoi scatenare un flame secondo me devi impegnarti di più, caro il mio guerrafondaio :)

Staremo a vedere... :incazzed:
Ad ogni modo non capisco questo odio da checche isteriche nei confronti del 'goto' quando nei linguaggi di oggi ci sono cose molto più complicate che ti permettono di scrivere bug molto più difficili da trovare ('template' black magik in C++, 'synchronized' voodoo in Java, ecc...ecc...).

vendettaaaaa
26-01-2012, 12:50
play() dovrebbe essere chiamata nel do-while, non contenerlo. E' una bella differenza, dato che poi ti serve anche un'altra funzione che contiene il do-while :D
Questo ha l'ovvio vantaggio che puoi chiamare play() come vuoi, non necessariamente causando un do-while, isolando l'idea di "eseguire un solo gioco dall'inizio alla fine".
Noterai che se ci metti il do-while quello che fa la funzione è "eseguire giochi finchè l'utente non ferma" che unisce molta più roba passando da funzione di pura logica di gioco a funzione con input, etc oltre al suo scopo originale di eseguire il gioco.
Modellizza fratello, modellizza! (semicit.)
Intendevo ovviamente di mettere play() dentro al do while...mi spiace di averti fatto scrivere un post per niente :o
Cmq modellizzo modellizzo, da buon ingegnere :D
@banryu: leggerò il tutto sul pc più tardi :)
EDIT: ho dato un'occhiata veloce, anche perchè la sintassi di Java un po' confonde le mie ancora non ben consolidate idee. Praticamente hai incapsulato in alcune classi tutto quello che serve per ricevere da utente il percorso di un file immagine e come ritagliarlo, per riutilizzare quel codice ogni volta che vuoi. E' appunto quello che voglio fare prima o poi per l'input dei miei programmi per evitare ogni possibile errore lato utente nella loro esecuzione :D

banryu79
26-01-2012, 13:19
Ad ogni modo non capisco questo odio da checche isteriche nei confronti del 'goto' quando nei linguaggi di oggi ci sono cose molto più complicate che ti permettono di scrivere bug molto più difficili da trovare.
E' proprio questo il motivo: il goto per farsi male è roba superata, oggi c'è roba migliore e più divertente; il goto è così noioso :asd:

!fazz
26-01-2012, 13:29
Essendo un programmino del menga non sono stato a creare una funzione nella classe Memory per ogni "funzione logica" che serve, certo che se faccio myGrid.play() posso tranquillamente metterci un do while!
Cmq sia, detto alla tua maniera suona già meglio...

occhio che tu non usi manco una classe e comunque ti abbiamo detto di usare funzioni non classi il tuo programma va benissimo procedurale ma che sia fatto con tutti i crismi della programmazione procedurare quindi usa le funzioni quando necessario :D

vendettaaaaa
26-01-2012, 13:55
occhio che tu non usi manco una classe e comunque ti abbiamo detto di usare funzioni non classi il tuo programma va benissimo procedurale ma che sia fatto con tutti i crismi della programmazione procedurare quindi usa le funzioni quando necessario :D
Non ho riportato gli altri file cmq uso una classe Memory che ho creato io, e myGrid è un oggetto di quella classe...

!fazz
26-01-2012, 14:12
Non ho riportato gli altri file cmq uso una classe Memory che ho creato io, e myGrid è un oggetto di quella classe...

ok


comunque, domanda banale visto che non sai ancora nulla di programmazione in c++ perchè complicarti la vita con le classi? impara bene la programmazione procedurale e solo dopo questa ( e un bello studio sulla gestione della memoria dinamica) potrai passare alle classi.

il tuo programma non necessita di OO, inizia dall'uso corretto delle funzioni degli operatori, della gestione dell'input e dell'output altrimenti rischi di voler costruire un grattacielo senza avere le fondamenta= crolla tutto e non riesci a cavar fuori un ragno dal buco

demos88
26-01-2012, 14:22
E' proprio questo il motivo: il goto per farsi male è roba superata, oggi c'è roba migliore e più divertente; il goto è così noioso :asd:
Se il linguaggio di programmazione mette a disposizione costrutti iterativi, il goto può (e deve) essere evitato: praticamente va sempre evitato, a meno che non si scriva in codice assembly (usando i jump, che sono di fatto dei goto che alterano la posizione puntata dal program counter).

!fazz
26-01-2012, 14:26
Se il linguaggio di programmazione mette a disposizione costrutti iterativi, il goto può (e deve) essere evitato: praticamente va sempre evitato, a meno che non si scriva in codice assembly (usando i jump, che sono di fatto dei goto che alterano la posizione puntata dal program counter).

JNZ ftw :D :D :D

vendettaaaaa
26-01-2012, 14:37
ok


comunque, domanda banale visto che non sai ancora nulla di programmazione in c++ perchè complicarti la vita con le classi? impara bene la programmazione procedurale e solo dopo questa ( e un bello studio sulla gestione della memoria dinamica) potrai passare alle classi.

il tuo programma non necessita di OO, inizia dall'uso corretto delle funzioni degli operatori, della gestione dell'input e dell'output altrimenti rischi di voler costruire un grattacielo senza avere le fondamenta= crolla tutto e non riesci a cavar fuori un ragno dal buco
Perché l'esercizio che ho seguito diceva di creare una classe per giocare a memory...ma poi cosa c'è di male? Praticamente ho scritto delle funzioni per manipolare una matrice e poi le ho incapsulate in una classe...niente di che. Mi pare un esercizio semplice e di buon valore didattico per introdurre le basi delle classi: costruttore, distruttore, variabili private, le tipiche funzioni set get e print... Dici che è troppo per me? :rolleyes:

WarDuck
26-01-2012, 15:26
Se il linguaggio di programmazione mette a disposizione costrutti iterativi, il goto può (e deve) essere evitato: praticamente va sempre evitato, a meno che non si scriva in codice assembly (usando i jump, che sono di fatto dei goto che alterano la posizione puntata dal program counter).

Come ho già detto, c'è un motivo per usare i goto, soprattutto in C puro: il cleanup di aree di memoria allocate e che non verranno utilizzate perché più avanti nel codice si è verificato un errore.


void Funzione()
{
/* alloc */

/* check alloc */
/* if errore goto error_handler; */

/* altri check vari */
/* if errore goto error_handler;

/* allocazioni e check vari */
/* if errore goto error_handler; */

return 0;

error_handler:
/* cleanup di tutte le strutture (se) allocate all'interno della funzione*/

return -1;
}


E' solo un esempio, come ho già detto si possono usare delle funzioni (inline o meno) per effettuare il cleanup, però questo implica che la funzione esterna sappia cosa allochi all'interno.

A meno che usi un gestore della memoria scritto da te che tenga traccia di tutte le allocazioni effettuate da una data funzione (non sarebbe neanche difficile da fare), e venga usata una macro RETURN che faccia in automatico la pulizia.

Il goto è uno strumento "general purpose", ci puoi fare tutto, ma se il linguaggio ti da strumenti specifici per gestire determinate situazione è chiaramente meglio usare quelli, per evitare lo spaghetti code.

demos88
26-01-2012, 15:45
Come ho già detto, c'è un motivo per usare i goto, soprattutto in C puro: il cleanup di aree di memoria allocate e che non verranno utilizzate perché più avanti nel codice si è verificato un errore.

Si certo, casi particolari dove la struttura iterativa non è sufficiente... ma sono appunto casi particolari, non vorrei dire menate, ma mi pare che pure nel kernel linux sia molto usato il goto proprio a tale scopo.
Così come anche il costrutto try catch del java può essere visto come una implementazione particolare di goto, che in caso di eccezione sposta l'esecuzione del codice a un'altra riga nella quale tipicamente la gestisci (ed eventualmente cancelli riferimenti, reimposti variabili...).
Il motivo per cui ad ogni livello didattico è sconsigliato l'uso di GOTO è che nel 99,9% dei casi, il goto non è indispensabile ed è meglio risparmiarselo.
Nell'ottica della domanda dell'autore del thread penso che fosse il senso da dare alla risposta.
Ciò non toglie che per tratti di codice performance critical il GOTO possa tornare utile laddove non vi sono alternative altrettanto valide.

!fazz
26-01-2012, 16:01
Perché l'esercizio che ho seguito diceva di creare una classe per giocare a memory...ma poi cosa c'è di male? Praticamente ho scritto delle funzioni per manipolare una matrice e poi le ho incapsulate in una classe...niente di che. Mi pare un esercizio semplice e di buon valore didattico per introdurre le basi delle classi: costruttore, distruttore, variabili private, le tipiche funzioni set get e print... Dici che è troppo per me? :rolleyes:

si è troppo,

comincia dalle cose semplici (non sei capace di acquisire da tastiera un intero in maniera corretta e vuoi pensare alle classi? ps nell'altro thread ti ho postato come si fà)

impara bene le basi del c++ (operatori, iteratori, funzioni, passaggio parametri per valore e per riferimento )studiati bene la memoria dinamica (puntatori, liste dinamiche ecc ecc l'allocazione dinamica è fondamentale per capire bene costruttori e distruttori delle classi),

una volta che non avrai problemi con le basi puoi passare all'OO ma non prima altrimenti mischi troppe cose lacunose, non capisci perchè sbagli e quindi non progredisci.

all'epoca uno dei miei professori ci martellava costantemente con un solo acronimo: KISS (Keep It Simple Stupid) ovvero mai fare una cosa più complicata del necessario, e credimi è fondamentale.

chi và piano và sano e và lontano, può far ridere ma è così.

Imho, dovresti provare a rifare il gioco completamente procedurale e strutturando bene il codice (usa le funzioni e non usare i goto), poi confronta i due listati e noterai subito la differenza :D

vendettaaaaa
26-01-2012, 16:20
si è troppo,

comincia dalle cose semplici (non sei capace di acquisire da tastiera un intero in maniera corretta e vuoi pensare alle classi? ps nell'altro thread ti ho postato come si fà)

impara bene le basi del c++ (operatori, iteratori, funzioni, passaggio parametri per valore e per riferimento )studiati bene la memoria dinamica (puntatori, liste dinamiche ecc ecc l'allocazione dinamica è fondamentale per capire bene costruttori e distruttori delle classi),

una volta che non avrai problemi con le basi puoi passare all'OO ma non prima altrimenti mischi troppe cose lacunose, non capisci perchè sbagli e quindi non progredisci.

all'epoca uno dei miei professori ci martellava costantemente con un solo acronimo: KISS (Keep It Simple Stupid) ovvero mai fare una cosa più complicata del necessario, e credimi è fondamentale.

chi và piano và sano e và lontano, può far ridere ma è così.

Imho, dovresti provare a rifare il gioco completamente procedurale e strutturando bene il codice (usa le funzioni e non usare i goto), poi confronta i due listati e noterai subito la differenza :D
Ok ma nell'altro post alla tua soluzione ci sono arrivato alle 9 di stamattina, però mi sa che ti sei perso quel mio messaggio :D
Cmq so già fare qualcosa di concreto, non parto da zero...ho 26 anni, una laurea magistrale in ingegneria chimica che mi ha formato secondo una certa mentalità...
E poi son fatto così: preferisco apprendere in modo trial&error piuttosto che seguire rigidamente un binario, se qualcosa mi incuriosisce ci provo. Manca un po' di disciplina, o meglio di "metodo", però credo di potercela fare tranquillamente. Se non so prendere un intero in input, ci provo, ci ragiono e ci arrivo :)

!fazz
26-01-2012, 16:45
Ok ma nell'altro post alla tua soluzione ci sono arrivato alle 9 di stamattina, però mi sa che ti sei perso quel mio messaggio :D
Cmq so già fare qualcosa di concreto, non parto da zero...ho 26 anni, una laurea magistrale in ingegneria chimica che mi ha formato secondo una certa mentalità...
E poi son fatto così: preferisco apprendere in modo trial&error piuttosto che seguire rigidamente un binario, se qualcosa mi incuriosisce ci provo. Manca un po' di disciplina, o meglio di "metodo", però credo di potercela fare tranquillamente. Se non so prendere un intero in input, ci provo, ci ragiono e ci arrivo :)

avrai anche una laurea in ingegneria chimica ma ci c++ stai a zero

il tuo approccio (il classico da smanettone) è perfetto per imparare le basi ma appunto per questo inizia a ragionare e risolvere i problemi partendo dai più semplici altrimenti ti perdi nel marasma

anche nella chimica, non penso che sei partito a studiare chimica dalle redox no?

vendettaaaaa
26-01-2012, 17:01
avrai anche una laurea in ingegneria chimica ma ci c++ stai a zero

il tuo approccio (il classico da smanettone) è perfetto per imparare le basi ma appunto per questo inizia a ragionare e risolvere i problemi partendo dai più semplici altrimenti ti perdi nel marasma

anche nella chimica, non penso che sei partito a studiare chimica dalle redox no?
No infatti...
Cmq se puoi linkarmi del materiale apposta (esercizi) faccio volentieri, altrimenti vado avanti con quel che ho trovato (sto facendo, in ordine e senza saltare nulla, gli esercizi di un corso che tengono a Parma (http://www.ce.unipr.it/people/tomamic/sites/default/files/esercizi.pdf) e sono arrivato alle classi, es. 5.4), non posso inventarmi le cose dal nulla :D

!fazz
26-01-2012, 17:09
No infatti...
Cmq se puoi linkarmi del materiale apposta (esercizi) faccio volentieri, altrimenti vado avanti con quel che ho trovato (sto facendo, in ordine e senza saltare nulla, gli esercizi di un corso che tengono a Parma (http://www.ce.unipr.it/people/tomamic/sites/default/files/esercizi.pdf) e sono arrivato alle classi, es. 5.4), non posso inventarmi le cose dal nulla :D

per me meglio se ti basi su un libro di esercizi che prendere spunto da una presentazione (cmq l'ordine di argomenti mi pare mal fatto in quella presentazione) in maniera da avere svariati esercizi spiegati passo passo un qualsiasi libro di esercitazioni di fondamenti di informatica può andare bene

vendettaaaaa
26-01-2012, 17:14
per me meglio se ti basi su un libro di esercizi che prendere spunto da una presentazione (cmq l'ordine di argomenti mi pare mal fatto in quella presentazione) in maniera da avere svariati esercizi spiegati passo passo un qualsiasi libro di esercitazioni di fondamenti di informatica può andare bene
Già ordinati ieri da Amazon, magari li conosci: ho ordinato Accelerated C++, ho letto svariate opinioni e dicono sia uno dei libri migliori per cominciare perchè spiega il C++ per esempi ed esercizi; e poi Programming: Principles and Practice Using C++ di Stroustrup...nel frattempo faccio questi che male non fanno :D

!fazz
26-01-2012, 17:43
Già ordinati ieri da Amazon, magari li conosci: ho ordinato Accelerated C++, ho letto svariate opinioni e dicono sia uno dei libri migliori per cominciare perchè spiega il C++ per esempi ed esercizi; e poi Programming: Principles and Practice Using C++ di Stroustrup...nel frattempo faccio questi che male non fanno :D

non li conosco ma direi che per iniziare possano andare bene