İngilizce D.learn haber grubunda şu soru soruldu:
http://forum.dlang.org/thread/qrzbwbxckmpkuhwnwjzc@forum.dlang.org
H. S. Teoh'un yanıtını beğendim ve Türkçe'ye çevirdim.
Hep başıma geldiği gibi, şu üç deyimi aynı anlamda kullandım: "referans olmak", "işaret etmek", "erişim sağlamak".
Ali
On Mon, Dec 01, 2014 at 04:42:36AM +0000, WhatMeWorry via Digitalmars-d-learn wrote:
>D'nin referans türlerinin (sınıflar, dinamik diziler, vs.) her zaman için
dinamik bellekte (heap) olduklarını söyleyebilir miyiz? Benzer biçimde,
değer türleri (yapılar, statik diziler, vs.) de her zaman için program
yığıtında (stack) mıdırlar? Yoksa böyle söyleyince konuyu fazla mı
basitleştirmiş oluyoruz?
Fazla basitleştirildiği doğru çünkü değer türleri de dinamik bellekte bulunabilirler (örneğin, BirYapı* gösterge = new BirYapı(...)
). Ancak, hem buna nadiren gerek duyulur hem de gerek duyulduğunda class kullanmak aslında daha uygun olur. Ek olarak, sınıf nesnelerini program yığıtında (veya yapı nesnelerini dinamik bellekte) kuran emplace() de var; ve statik sınıf dizilerinin elemanları da dinamik bellekte olmak zorundadır çünkü onların yerleştirilecekleri program yığıtı yoktur.
Sormamın nedeni, yapıların sınıf üyeleri olabileceği gibi sınıfların da yapı
üyeleri olabilir, değil mi? Öyleyse, böyle karışık türler konusunda ne
söyleyebiliriz? Değer veya referans türü olması en dıştaki türün hangi
çeşitten olduğuna mı bağlıdır?
Öyle düşünmek açıklamaya yetmiyor. Daha uygun olan bir düşünce tarzı şöyle: değer türü == "tam burada bulunan" ve referans türü == "başka bir yerde bulunan". Örneğin, şöyle bir yapı olsun:
struct S {
int x;
}
main() içinde S türünden bir değişken tanımlandığında S'nin içeriği "tam burada"dır. Yani, işlevin işletilmesi sırasında program yığıtındadır:
void main() {
S s; // "tam burada", yani program yığıtında
}
S türünde bir üye tanımlandığı durumda da S'nin içeriği onu içeren kapsamdadır:
class C {
S s; // s, C'nin içeriğinin parçasıdır
}
struct T {
S s; // s, T'nin içeriğinin parçasıdır
}
Bunu aşağıdaki şekil ile gösterebiliriz:
'
+--C nesnesi--+
| +---S s---+ |
| | int x; | |
| +---------+ |
+-------------+
'
Üye s, C değişkeninin yaşadığı bellek bloğunun bir parçasıdır.
Öte yandan, bir sınıf nesnesi "başka bir yerde"dir. C türünde bir değişken tanımlandığında o değişken nesnenin kendisi değil, başka bir yere işaret eden bir göstergedir:
void main() {
C c = new C();
}
'
Program yığıtında: Dinamik bellekte:
+------C c------+ +--C nesnesi--+
| --------> | +---S s---+ |
+---------------+ | | int x; | |
| +---------+ |
+-------------+
'
Görüldüğü gibi, c değişkeni program yığıtındadır ve asıl nesneyi içermemektedir; c, asıl nesnenin bulunduğu dinamik bellekteki bir yere işaret etmektedir.
Yapı içinde sınıf olan duruma bakalım.
struct U {
int y;
C c;
}
void main() {
U u;
}
'
Program yığıtında: Dinamik bellekte:
+----U u------------+ +--C nesnesi--+
| int y; | | +---S s---+ |
| +---C c---------+ | | | int x; | |
| | ---------->| +---------+ |
| +---------------+ | +-------------+
+-------------------+
'
Görüldüğü gibi, u oldukça ilginç bir nesnedir çünkü kendisi hem program yığıtında hem de dinamik bellekte bulunmaktadır! Kendisinin 'int y' ve 'c' parçaları program yığıtındadır ama 'c'nin işaret ettiği nesne dinamik bellektedir. U'nun yığıtta bulunan parçaları değer türünde olan üyeleridir, c parçası ise referans türündedir -- örneğin, aşağıdaki ifadeyi işletelim:
U v = u;
v, 'int y' üyesinin bir kopyasını içerir ama 'C c' üyesi u'nun da işaret etmekte olduğu aynı C nesnesidir:
'
Program yığıtında: Dinamik bellekte:
+----U u------------+ +--C nesnesi--+
| int y; | | +---S s---+ |
| +---C c---------+ | | | int x; | |
| | ---------->| +---------+ |
| +---------------+ | +-------------+
+-------------------+ ^
|
+----U v------------+ |
| int y; | |
| +---C c---------+ | |
| | ------------------+
| +---------------+ |
+-------------------+
'
u.y ve v.y değişkenlerinde değişiklik yapmak karışıklık yaratmaz. Ancak, u.c'yi değiştirmek v.c'yi de değiştirecektir çünkü her ikisi de dinamik bellekteki aynı nesnenin referansıdır.
Bunun hangi durumlarda yararlı olabileceğini merak ediyor olabilirsiniz. D dilimlerinin bu kadar kullanışlı olmalarının temeli aslında buna dayanır: Dinamik diziler perde arkasında bir adet değer türündeki üyeden, bir adet de referans türündeki üyeden oluşurlar:
struct _d_array(T) {
size_t length;
T* ptr;
}
Bir dizinin bir dilimi alındığında bu türden bir yapı nesnesi kopyalanır ve onun .length ve .ptr üyelerine uygun değerler atanır; artık iki farklı kopya dinamik bellekte bulunan aynı diziye erişim sağlamaktadırlar. Buradaki önemli nokta, _d_array'in değer türü olması nedeniyle başlangıçtaki dilim nesnesinin değişmemiş olması, buna rağmen _d_array'in referans üyesi sayesinde asıl elemanların yeni dilim yoluyla da değiştirilebilmesidir. Örnek:
void main() {
int[] a = [1,2,3]; // asıl dizi
int[] b = a[0 .. 1]; // asıl dizinin bir dilimi
assert(a == [1,2,3]); // asıl dilim değişmez
b[0] = 4; // dizi içeriği yeni dilim yoluyla değişebilir
assert(a[0] == 4); // ve bu asıl dizide de gözlemlenir
}
> Sormadan edemeyeceğim. Belki de kendim denemeliyim ama bir yapı üyesinin
sınıf üyesinin yapı üyesinin sınıf üyesinin... gibi bir durum olsa? Buna
hangi durumlarda gerek olabileceğini bilmiyorum ama teoride de olsa sormak
istedim.
[...]
Aslında hiç de teoride kalan bir soru değildir. Farkında bile olmadan dizi dilimi olarak zaten her gün kullanıyorsun. :-) Örneğin, aşağıdaki dizi dizisine bakalım:
int[][] dizi;
'dizi', değer türü .length üyesinden ve referans türü .ptr üyesinden oluşan _d_array türünde bir değişkendir. 'dizi'nin .ptr üyesi, kendileri _d_array türünde olan elemanlara erişim sağlar; bu üyelerin kendi .length üyeleri (bunlar dinamik bellektedir!) ve kendi .ptr üyeleri vardır (bunlar alt dizilere işaret ederler). Bir başka deyişle, .length üyeleri "tam burada"dırlar ('dizi' değişkenininki program yığıtında olabilir ama alt dizilerinki dinamik bellektedir) ama .ptr üyeleri "başka bir yerde" olan elemanlara işaret ederler (normalde dinamik bellektedirler ama emplace() ile herhangi bir yerde de bulunabilirler).
T
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]