Moi
Alla oleva koodi toimii kyllä en ole varma onko se nyt aivan "oikeanlaista" koodia monia asia virheitä voi olla.. Elikkäs kysymys kuuluu kuinka voin palauttaaa moniulotteisen taulukon?
#include <stdio.h> unsigned short *palautaTaulukko(); int main(int argc[], char *argv[]){ unsigned short *buffer = new unsigned short[10]; buffer = palautaTaulukko(); for(int i=0;i<10;i++){ printf("Luku %d: %d\n", i, buffer[i]); } } unsigned short *palautaTaulukko(){ unsigned short Taulukko[10] = {255, 1, 200, 132, 2, 1, 25, 1, 300, 111};; return Taulukko; }
Tällä tavalla tämä ei toimi..(alla) kaikki neuvot ovat tervetulleita, olisi kiva oppia taas jotain pientä uutta =)
#include <stdio.h> unsigned short *palautaTaulukko(); int main(int argc[], char *argv[]){ unsigned short *buffer = new unsigned short[2][10]; buffer = palautaTaulukko(); } unsigned short *palautaTaulukko(){ unsigned short Taulukko[2][10]; //Taulukko saa nyt olla tyhjä. //Tämä palautus ei mene enää kääntäjästä läpi, joten main:ssa olevaa //sijoitusta ei enää voitasi edes tehdä.. enkä sen oikeellisuudesta ole varma return Taulukko; }
#include <stdio.h> unsigned short *palautaTaulukko(); int main(int argc[], char *argv[]){ unsigned short *buffer = NULL; buffer = palautaTaulukko(buffer); } unsigned short *palautaTaulukko(){ unsigned short *Taulukko = new unsigned short[2][10]; return Taulukko; }
Hmm.... ei mene VS2005 läpi toi koodin pätkä.
tuon parametri virheen kyllä ymmärrän minkä takia tulee, mutta tuo toinen virhe on edelleenkin hieman ymmärrettävissä, mutta juuri tuon takia kysyin neuvoa, koska en tiedä miten tuo pitäisi korjata.
Error1: error C2660: 'palautaTaulukko' : function does not take 1 arguments
Error2: error C2440: 'initializing' : cannot convert from 'unsigned short (*)[10]' to 'unsigned short *'
Yleistä: 2-ulotteinen taulukko vaatii muodokseen '**', pelkkä '*' ei riitä.
Virhe 1: funktio on määritelty parametrittomana, mutta kutsut sitä parametrin kanssa (buffer).
Virhe 2: *Taulukko on pointteri; new unsigned short[][] palauttaa listan osoittimia jota taas ei voi suoraan konffata yksittäiseksi osoittimeksi.
Lisäksi: näen vaarallisia muistinvarauksia, joita ei ole mahdollista vapauttaa tuota systeemiä käyttäen.
Vastaus alkuperäiseen kysymykseen on: Et mitenkään, sillä C:ssä ja C++:ssa ei ole kaksiulotteisia taulukoita. Koska on ihan satavarmaa, ettei tämä vastaus kelpaa, pitäisi ensiksi kysyä, että mitä oikein ollaan tekemässä, niin sitten voisi vähän hahmotella toimivia ratkaisuja.
Kaksiulotteisia taulukoita ei ole, vaan ne ovat taulukkoja sisältäviä taulukkoja. Hommaa sotkee vielä se, että C:n perintönä taulukot rappeutuvat pointtereiksi silloin, kun niitä välitetään funktioiden parametreina tai paluuarvoina. Funktiosta voi palauttaa taulukon vain, jos se on esmes structin sisällä.
No, jos homman ei tarvitse toimia kovin dynaamisesti, eli vähintäänkin taulukon sisältämän taulukon koko on tiedossa, homma menee näin (ellen kovin pahasti mokaa syntaksin kanssa):
unsigned short (*palautaTaulukko())[10]; int main(int argc[], char *argv[]){ unsigned short (*buffer)[10] = 0; buffer = palautaTaulukko(); // buffer pitäisi deletoidakin joskus... } unsigned short (*palautaTaulukko())[10] { unsigned short (*taulukko)[10] = new unsigned short[2][10]; return taulukko; }
Muut vaihtoehdot ovat toinen toistaan kamalampia pointteritaulukkovirityksiä, joista ei tositilanteessa pysy pirukaan kärryillä. Pelastus löytyy kääräisemällä koko hoito järjellisen luokkarajapinnan sisään.
Onpa tästä muuten yksi koodivinkkikin. Siinä olisi aika valmista tavaraa, oikeastaan vain swap-funktio puuttuu. Mutta sitten ollaankin jo niin pitkällä, että koodaaja tajuaa itsekin ettei kaksiulotteinen taulukko taida sittenkään olla paras tietorakenne hänen ongelmaansa.
Edit: Typoja koodissa.
Et voi palauttaa suurempaa kuin mikä on järjestelmän maksimi eli 32 -bittisellä tavallisesti kokonaislukuna 4 tavua tai liukulukuna 8 tavua (poikkeuksena tietysti SSE -rekisterit). Siihen ei auta structit eikä mitkään luokat. Näin ollen tässä tapauksessa paluuarvo on oltava siis osoitin johonkin eli ei itse taulukko.
Minkä hyvänsä taulukon voi mieltää yksi- tai moniulotteisena. Esim. int a[2][3]={1,2,3,4,5,6} on sama kuin int a[2][3]={{1,2,3},{4,5,6}} tai int a[3][2]={{1,2},{3,4},{5,6}} tai int a[6]={1,2,3,4,5,6}. Tuo moniulotteisuus on siis vain C -kielistä merkintää eikä sillä ole suorittimen kannalta merkitystä, koska kaikki tieto on todellisuudessa peräkkäin. Ainut millä on merkitystä, on se miten haluat asiat mieltää, ja miten koodi on helpoiten tajuttavissa. Jos siis kopioit taulukkolaskennasta taulukon, jossa on rivejä ja sarakkeita, taulukon rakennetta ei kannata muuttaa yksiulotteiseksi.
#include <stdio.h> unsigned short *palautaTaulukko(); int main(int argc[], char *argv[]){ unsigned short *buffer = NULL; buffer = palautaTaulukko(); delete buffer; return 0; } unsigned short *palautaTaulukko(){ unsigned short *Taulukko = (unsigned short *)(void*) new unsigned short[2][10]; return Taulukko; }
Kun palautat taulukon osoitteena, menetät siis vain tiedon taulukon koosta (kääntäjä menettää). Näin ollen osoitinta käytettäessä on ajateltava tässä vaiheessa, että taulukko on yksiulotteinen. Jotta pääset seuraavalle riville osoittimella pi = a[2][10], niin lisäät vain osoittimeen pi+ = 10.
pasic kirjoitti:
Et voi palauttaa suurempaa kuin mikä on järjestelmän maksimi eli 32 -bittisellä tavallisesti kokonaislukuna 4 tavua tai liukulukuna 8 tavua (poikkeuksena tietysti SSE -rekisterit). Siihen ei auta structit eikä mitkään luokat. Näin ollen tässä tapauksessa paluuarvo on oltava siis osoitin johonkin eli ei itse taulukko.
Höpöhöpö. Tämä on ihan toimivaa ja laillista koodia, vaikkakin tehotonta varsinkin suurilla taulukoilla:
struct taulu { unsigned short a[2][10]; }; taulu palautaTaulu() { taulu t; return t; } int main() { taulu u; u = palautaTaulu(); }
pasic kirjoitti:
Minkä hyvänsä taulukon voi mieltää yksi- tai moniulotteisena. Esim. int a[2][3]={1,2,3,4,5,6} on sama kuin int a[2][3]={{1,2,3},{4,5,6}} tai int a[3][2]={{1,2},{3,4},{5,6}} tai int a[6]={1,2,3,4,5,6}..
Nuo nyt kumminkin ovat kaikki eri tyyppejä.
Aiemmassa koodipätkässäni kääntäjä ei menettänyt tietoa, funktio palauttaa osoittimen paikkaan, jossa on kymmenen alkion mittainen taulukko; sitä, montako noita taulukoita siellä on, ei kääntäjä tokikaan tiedä. Sinun pätkässäsi palautetaan osoite paikkaan, jossa on yksi alkio; sitä, montako alkioita on tai miten ne on ryhmitelty, ei kääntäjä tiedä. Castauksilla sanotaan, että "pidä sinä kääntäjä turpasi kiinni äläkä valita, minä tiedän paremmin, mitä tässä on". Otetaan siis pois päältä kaikki automatiikka ja poistetaan suojaverkot. Just joo, näissähän ei yleensä satu kellekään virheitä, lisäät vain osoittimeen pi+ = 10.
Kirjoittamassani pätkässä on kommentti puuttuvasta deletestä. Siellä siis pitäisi jossain olla delete [] buffer;
. Sinun pätkässäsi pitäisi myös olla taulukko-delete, mutta periaatteessa sekin menee väärin, sillä nyt kääntäjä ei enää tiedäkään bufferin osoittelevan paikkaan, jossa on taulukoita. Pelkkä delete on joka tapauksessa virhe.
C-koodareilla tai C:tä C++:lla koodaavilla on hinku pyörittää hommaa uskomattomlla cast- ja pointterivirityksillä, vaikka kieli saattaa kyllä tarjota vähän muitakin apuja. Mutta jos ollaan C++:ssa, on aivan turhaa vaikeuksien kerjäämistä, ellei hommaa hoida sopivan luokkarajapinnan avulla.
Suosittelisin aloittamaan uudestaan C -kielen alkeista ja tutustumaan järjestelmiin. Tuo sinun koodisi osoittaa, ettet ymmärrä mitään mitä todellisuudessa tapahtuu.
Ensinnäkin järjestelmässä on pinomuisti. Varaat palautaTaulu -funktion alussa siitä sizeof(taulu) -kokoisen klöntin, jonka osoitteen otat talteen. Seuraavaksi pinomuisti tyhjenee funktion päätyttyä, joten palautettavaa osoitetta ei saa hyödyntää.
On siis täysi mahdottomuus palauttaa suurempaa kuin mitä järjestelmän rekisteri on ilman osoittimia. Osoitinkäsitteen voi tietysti naamioida näyttämään ikään kuin palauttaisit jotakin muuta. Todellisuudessa esimerkissäsi palautuu siis osoitin tauluun eikä itse taulu.
koo kirjoitti:
Et mitenkään, sillä C:ssä ja C++:ssa ei ole kaksiulotteisia taulukoita. Koska on ihan satavarmaa, ettei tämä vastaus kelpaa...
On todellakin varmaa, ettei vastaus kelpaa. Katso esim. C:n standardista mitä siellä asiasta sanotaan.
Koska tekijä pyysi neuvoja miten korjata koodi oikeaksi, en nähnyt tarvetta korjata koko koodia. Tietysti luokilla saavutetaan parempi tulos. Tässä tapauksessa jossain kohdassa koodia on silti pakko käyttää sitä deleteä, jotta varattu muisti vapautuisi. Ei sitä voi jättää pois, vaikka osoitinmuunnos olisi tapahtunut. Se delete ei siis tarvitse muuta kuin osoitteen varatun muistialueen alkuun toimiakseen. Periaatteessa toiminta new/delete on sama kuin C:n malloc/free.
Molemmat esimerkkipätkäni ovat täysin sääntöjenmukaista ja toimivaa koodia (varsinkin jos siihen ekaan vielä lisää sen puuttuvan taulukko-deleten), joten tässä täytyy olla kyseessä jonkun muun kuin minun ymmärtämykseni rajoista.
Juttu menee niin, että ohjelmointikielessä on omat abstraktiot sekä säännöt, joiden mukaan toimitaan. Näiden puitteissa kääntäjä voi toteuttaa asiat pinnan alla miten parhaaksi katsoo, kunhan näkyvä vaikutus on se, mitä säännöissä sanotaan.
Jos funktio on C:ssä esitelty struct foo func();
, sen paluuarvo ei ole pointteri, vaan structin arvo. Kääntäjä voi varata structille tilan mistä tykkää ja sisäisesti se voi käsitellä vaikka pointtereita, mutta koodaajalle kyseessä on nimetön tilapäinen muuttuja, joka elää ja voi hyvin, kun funktiokutsu palaa. Puheet pinovarauksista, osoitteen palautumisesta ja viittauksen virheellisyydestä ovat täyttä roskaa tässä yhteydessä.
Pinomuisti on vain abstraktio ja sen toteutus vaihtelee yleiskäyttöisissäkin prossuarkkitehtuureissa paljon. Joissakin on erityinen stack pointer ja sen osoittelemaa aluetta käytetään funktioiden kutsuparametrien ja paluuarvojen välittämiseen, joissakin se ei ole näin suoraviivaista. Mutta sillä ei ole mitään väliä, sillä C- tai C++-kielten säännöt ei sano halaistua sanaa siitä, onko masiinassa joku pino vai ei.
Sana multidimensional esiintyy C-standardissa tasan kaksi kertaa: kohdassa 6.5.2.1 Array subscripting ja kohdassa 6.7.5.2 Array declarators. Ekassa kohdassa kerrotaan mm. miten n-ulotteisesta taulukosta kuoriutuu n-1 -ulotteisia taulukoita, ja siellä on sitten ihan esimerkkikin, jossa sanotaan, että Consider the array object defined by the declaration int x[3][5];
Here x is a 3 × 5 array of ints; more precisely, x is an array of three element objects, each of which is an array of five ints. Toinen kohta on kommenttiteksti When several "array of" specifications are adjacent, a multidimensional array is declared. Hmm, array of what? Siis, kyllähän moniulotteisia taulukoita on, mutta ne ovat käsittelyltään taulukoita taulukkoja. Ja kaksiulotteisen taulukon alkion osoittaminen tapahtuu siis tyyliin t[1][2]
, ei t[1, 2]
, mikä myös kertonee jotakin.
Kun C++:ssa käytetään deleteä, sen pitää olla joko yksittäinen tai taulukko-delete sen takia, että destruktoreja kutsuttaisiin oikea määrä. Pointteria ei parane pahemmin castailla sen takia, että oliolle kutsuttaisiin oikeaa, sen omaa destruktoria. Tässä on aika iso ero malloc/free-toimintaan ja tämä on aika alkeita.
Jälkimmäisessä on vaan se vika, että se joskus toimii joskus ei. Se miksi se toimii joskus, johtuu siitä, että satuit kutsumaan palautaTaulu:a samalla kääntäjällä kuin mainia. Tuo osoittaa vaan sen, että kääntäjällä saa tehtyä paljon semmoista mikä menee läpi, mutta mikä ei todellisuudessa toimi. Kikkailuvinkkejä on monilla sivuilla, esim. tässä lisää: http://www.codeproject.com/cpp/clangtricks.asp
Aikaisempaan selostukseen täytyy siis lisätä, että funktiota kutsuttaessa on siis katseltava assembly -listauksesta miten kutsua.
koo kirjoitti:
Sinun pätkässäsi pitäisi myös olla taulukko-delete, mutta periaatteessa sekin menee väärin, sillä nyt kääntäjä ei enää tiedäkään bufferin osoittelevan paikkaan, jossa on taulukoita.
Jos taulukko luotiin: new unsigned short[2][10], ei kyseessä ole monta taulukkoa vaan yksi taulukko. Siksi siinä ei tarvita kuin yhtä deleteä.
Hyvä että löysit sen sanan: moniulotteinen taulukko ;)
pasic kirjoitti:
Jos taulukko luotiin: new unsigned short[2][10], ei kyseessä ole monta taulukkoa vaan yksi taulukko. Siksi siinä ei tarvita kuin yhtä deleteä.
Ei kukaan ole väittänytkään, että deletejä pitäisi olla monta. Sen sijaan kuuluisi olla delete []
. Perustyypeillä tuo näköjään menee läpi, mutta se ei tee siitä oikeampaa.
#include <iostream> class juttu { public: juttu() {std::cout << "juttu(); constructor.\n";} ~juttu() {std::cout << "~juttu(); destructor.\n";} }; int main(void) { juttu *vaarin = (juttu*)(void*)new juttu [2][3]; delete vaarin; return 0; }
juttu(); constructor. juttu(); constructor. juttu(); constructor. juttu(); constructor. juttu(); constructor. juttu(); constructor. ~juttu(); destructor. *** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x0804a00c *** ======= Backtrace: ========= /lib/tls/i686/cmov/libc.so.6(cfree+0x1bb)[0xb7db6f3b] /usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb7f74cf1] ./a.out(__gxx_personality_v0+0x288)[0x8048928] /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xdc)[0xb7d61ebc] ./a.out(__gxx_personality_v0+0x41)[0x80486e1] ======= Memory map: ======== (Väliäkö hällä.) Aborted
Kannattaisi uskoa, koo on kyllä oikeassa. C++:n standardi ei kaiketi edellytä, että eri kääntäjien toteutustapojen ja objektitiedostojen tulisi olla yhteensopivia, ja kuten jo mainittiin, kääntäjä saa hoitaa kielen rakenteiden toteutuksen käytännössä omalla tavallaan.
Ei todellakaan standardi sitä vaadi, mutta mitä järkeä on kirjoitella koodia joka ei toimi ???
pasic kirjoitti:
mitä järkeä on kirjoitella koodia joka ei toimi ???
Miten niin koodi ei toimi? Hyvinhän se toimii. Miksi pitäisi kääntää eri osat ohjelmasta eri kääntäjillä? Sinun koodisi sen sijaan ei toimi, kuten yllä näkyy.
Ei kyseessä ole yksin kääntäminen. Et voi kutsua funktiota muualta ilman turvautumista assembly kieleen.
Metabolix kirjoitti:
Sinun koodisi sen sijaan ei toimi, kuten yllä näkyy.
Tarkoituksena ei ollut muuttaa koko koodia vaan tehdä pienin muutoksin koodista toimivampi. Se todellakin menee kääntäjästä läpi, loppuu virheittä ja muistinvaraus poistuu.
Ihme inttämistä.
pasic kirjoitti:
Jälkimmäisessä on vaan se vika, että se joskus toimii joskus ei. Se miksi se toimii joskus, johtuu siitä, että satuit kutsumaan palautaTaulu:a samalla kääntäjällä kuin mainia.
Sanonpa nyt kolmannen kerran, että esimerkkini on täysin sääntöjen mukaista ja toimivaa koodia. Et ole esittänyt ainoatakaan paikkansa pitävää väitettä siitä, miksei näin olisi.
Nyt sitten yhtäkkiä repäiset todisteeksi vielä senkin, että homma ei toimi eri kääntäjillä ristiin. Joo ei, käännettyjen ohjelmien binääriyhteensopivuutta ristiin ei ole sinällään taattu koskaan missään. Nykyään eri kääntäjät saattavat kyllä noudattaa myös yhteisesti sovittuja binääritason rajapintoja eli ABI:ja. Mutta tällä ei siis ole mitään tekemistä kielen sääntöjen kanssa, koodipätkissäni ei ole minkäänlaista kikkailua.
pasic kirjoitti:
Tuo osoittaa vaan sen, että kääntäjällä saa tehtyä paljon semmoista mikä menee läpi, mutta mikä ei todellisuudessa toimi. Kikkailuvinkkejä on monilla sivuilla, esim. tässä lisää: http://www.codeproject.com/cpp/clangtricks.asp
Esimerkeilläni ei ole mitään tekemistä tuon pellesivun houruilujen kanssa. Sivuston temput eivät ole perusteltuja minkään syyn takia; jokainen niistä on toteutettavissa vähemmällä kikkailulla ihan laillisten ja siirrettävien rakenteiden avulla.
pasic kirjoitti:
Aikaisempaan selostukseen täytyy siis lisätä, että funktiota kutsuttaessa on siis katseltava assembly -listauksesta miten kutsua.
Höpöhöpö. Koodatakseen C:llä tai C++:lla ei tartte katsella assembly-koodia. Riittää, kun osaa C:tä tai C++:aa.
pasic kirjoitti:
Jos taulukko luotiin: new unsigned short[2][10], ei kyseessä ole monta taulukkoa vaan yksi taulukko. Siksi siinä ei tarvita kuin yhtä deleteä.
Sinä nyt vaan et sitten tajua näitä juttuja. Siis yksi delete, mutta sen pitää olla sellainen, että kutsutaan oikea määrä oikeanlaisia destruktoreja. Koodipätkäsi tekee virheen noissa molemmissa.
Vääränlainen delete voi toimia perustyyppien kanssa, koska niiden destruktorit eivät oletusarvoisesti tee mitään. Deleten muistinhallintapuoli sitten voi toimia tai olla toimimatta, kuten Metabolixin esimerkkikin näyttää.
pasic kirjoitti:
Hyvä että löysit sen sanan: moniulotteinen taulukko ;)
Joo, aika helppoahan se oli. Olisi varmaan onnistunut sinultakin, jos olisit koskaan itse edes avannut C- tai C++-standardin. Noiden yhä jatkuvien taulukkopuheittesi perusteella, ymmärsitkö mitään noita lainaamiani pätkiä standardista, vai pitääkö vielä pyytää jotakuta selittämään ne sinulle?
Jos meinaat vielä elvistellä muita perehtymään alkeisiin, järjestelmiin, ymmärtämään todellisuuden tapahtumia ja lukemaan standardia, voisit tehdä kotiläksysi pikkuisen paremmin.
Siispä kerran vielä alusta mikä toimii ja mikä ei:
- funktiota onnistuu kutsumaan samalla kääntäjällä, jolla taulukko on luotu
- funktiota ei pysty helposti kutsumaan muilla kääntäjillä / muualta
Seuraavassa esimerkki VC++ -kääntäjällä Windowsissa
_palautaTaulu@0: sub esp, 40 ;Tässä varataan tilaa taulukkoa varten ;Tästä alkaa taulukon siirto pääohjelmaan mov ecx, 10 ;Siirrettävä määrä lea esi, DWORD PTR _t$[ebp] ;Lähde mov edi, DWORD PTR $T52960[ebp] ;Kohde rep movsd ;Siirto mov eax, DWORD PTR $T52960[ebp] ;Kohteen osoite palautetaan pääohjelmalle add esp, 40 ;Poistetaan muistivaraus ret 4 ;Funktio palaa _main: sub esp, 112 ;Tehdään muistivaraus (2 x taulukon koko + lisät) lea eax, DWORD PTR $T52962[esp] ;Osoite, johon taulukko haluttaisiin push eax ;Osoite parametriksi call _palautaTaulu@0 ;Kutsutaan funktiota ;Tehdään uusi taulukon siirto mov ecx, 10 ;Siirrettävä määrä mov esi, eax ;Lähde lea edi, DWORD PTR _u$[ebp] ;Kohde rep movsd ;Siirto add esp, 112 ;Muistivaraus päättyy ret 0 ;Ohjelma loppuu
Aluksi mikä menee pieleen on, että funktiolla ei nimen mukaisesti ole parametreja (eli sama kuin koodissa), mutta silti sille annetaan yksi parametri. Mitä et voi olettaa:
- että muut kääntäjät voisivat käyttää funktiota
- että muista ohjelmista voisi kutsua funktiota
- lisäksi koska kumpainenkaan - standardi eikä kääntäjän opas - kerro mitä tuossa tapahtuu, et voi luottaa että kyseisen kääntäjän tulevat versiot toimisivat samalla menetelmällä
Siis esimerkiksi wintoosassa dll -kirjastoon kyseistä funktiota ei voi sijoittaa ilman assemblyn tuntemista.
Mitä omaan kyhäelmääni tulee, niin delete poistaa muistivaraukset perustyyppiä olevalta taulukoilta, jotka siis new:llä varasin. Seuraavassa esimerkki VC++ -kääntäjällä koodistani:
_palautaTaulukko: push 40 ;taulukon koko call operator_new ;nimensä mukainen toiminta add esp, 4 ;edellinen on cdecl -tyyppinen, joten pino oikeaksi ret 0 ;funktio päättyy _main: sub esp, 4 ;Varataan tilaa muuttujalle mov DWORD PTR _buffer$[esp], 0 ;Tyhjennetään muuttuja call _palautaTaulukko ;kutsutaan funktiota push eax ;edellisen paluuarvo annetaan parametriksi call operator_delete ;nimensä mukainen toiminta add esp, 4 ;jälleen cdecl -funktio xor eax,eax ;paluuarvo poistuttaessa add esp, 4 ;Muistivaraus päättyy ret 0 ;ohjelma päättyy
Oletusarvoisesti kun annan siis perustyyppiä olevan osoittimen, delete poistaa muistivarauksen HeapFree -funktiolla (sama mitä C:n free käyttää). new puolestaan (_palautaTaulukko) kutsuu edellä HeapAlloc -funktiota (samaa kuin C:n malloc käyttää). Eli ei ongelmia toimivuuden kanssa. Toimintoihin viitataan standardissa 'default definitions for the global allocation functions'. Tietty standardi ei ota kantaa käytetäänkö minkälaisia/nimisiä funktioita new:ssa / delete:ssä.
Aiemmin puhuttiin siitä, että koodipätkäni ei olisi sääntöjen mukaista toimivaa koodia. Nyt kaivellaan sitten sitä, että
pasic kirjoitti:
- funktiota ei pysty helposti kutsumaan muilla kääntäjillä / muualta
vaikka tuo liittyy juurikin siihen, että kukin kääntäjä saa toteuttaa asiat pinnan alla ihan niin kuin tykkää, kunhan lopputulos on se, mitä kielen säännöt sanovat. Nuo jutut saattavat hyvin vaihdella eri kielissä, eri kääntäjillä, kääntäjän eri versioilla ja saman version eri käännösoptioilla.
Joillakin alustoilla jotkut kääntäjät noudattavat samoja binäärirajapintamäärityksiä, joten noissa tapauksissa funktioita ja luokkia voi käyttää ristiin rastiin.
pasic kirjoitti:
Mitä omaan kyhäelmääni tulee, niin delete poistaa muistivaraukset perustyyppiä olevalta taulukoilta, jotka siis new:llä varasin.
Jännää, vatupassilla naulojen iskeminen näyttää jollakin taas toimivan! Kuule, sen lisäksi että koodipätkässäsi on undefined behaviour, voitko olettaa:
pasic kirjoitti:
- että muut kääntäjät voisivat käyttää funktiota
- että muista ohjelmista voisi kutsua funktiota
- lisäksi koska kumpainenkaan - standardi eikä kääntäjän opas - kerro mitä tuossa tapahtuu, et voi luottaa että kyseisen kääntäjän tulevat versiot toimisivat samalla menetelmällä
Jotenkin nuo kun tuntuvat olevan ongelmia koodipätkissäni, mutta sinun esimerkkiäsi ne ei sitten vaivaakaan, vaikka siinä on lisäksi vielä ohjelmointivirhe?
Kerro nyt ihmeessä, mikä se juttu on, mikä tekee sääntöjen mukaisesista ja toimivista koodipätkistäni jotenkin merkillisesti käyttökelvottomia, jos niitä muutoin koskee ihan samat vaatimukset, kuin mitä on asetettu sinun sattumalta toimivalle bugiselle koodillesi!
pasic kirjoitti:
Toimintoihin viitataan standardissa 'default definitions for the global allocation functions'.
Pikkuisen hätäisesti kaivelit C++-standardin esiin, taisi jäädä aika monta muuta juttua lukematta. No, vaikket mitään lukisikaan, Metabolix jo konkreettisesti demosi, mitä koodillesi tapahtuu, jos taulukon alkioille on määritelty destruktorit.
pasic oletko aivan varmasti lukenut oikeaa opasta kun opettelit C:tä?
Aihe on jo aika vanha, joten et voi enää vastata siihen.