İşaretçiye yeni bir işaretçi tahsis etmek yasal mı?


33

İşlevlere işaretçiler, geçersiz işaretçi içinde saklanamayacakları için düz veri işaretçileri değildir. Yine de, bir fonksiyon işaretçisinin kopyasını aşağıdaki koddaki gibi dinamik bellekte (gcc ve clang olarak) saklayabildiğim görünüyor. C ++ Standardına göre böyle bir kod yasal mı, yoksa bu bir çeşit derleyici uzantısı mıdır?

Ayrıca, işlev işaretçisi için ortaya çıkan işaretçi düz bir veri işaretçisi gibi davranır: Ben void * depolamak ve static_cast tarafından void * alabilirsiniz. Bu davranış Standart tarafından garanti ediliyor mu?

int main()
{
  extern void fcn();
  void (*fcnPtr)() = &fcn;
  void (**ptrToFcnPtr)() = nullptr;

  //Make the copy of fcnPtr on the heap:
  ptrToFcnPtr = new decltype(fcnPtr)(fcnPtr);
  //Call the pointed-to function : 
  (**ptrToFcnPtr)();

  //Save the pointer in void* :
  void *ptr = ptrToFcnPtr;
  //retrieve the original ptr: 
  auto myPtr = static_cast< void(**)() > (ptr) ; 
  //free memory:
  delete ptrToFcnPtr ;

}

2
Lütfen ham funciton işaretçileri kullanmayın. std::functionBunun yerine kullanın .
Bazı programcı dostum

Buna gerek yok newetmek döküm için void*. bir işlev değil, bir nesne olduğu için void* ptr = &fcnPtr;de aynı şekilde çalışır fcnPtr.
ceviz

5
@Someprogrammerdude std::function, isteğe bağlı olarak çağrılabilir depolamak için türden silinen bir kaptır, işlev işaretçileri için bir yedek değildir ...
Michael Kenzel

7
(@Someprogrammerdude) Lütfen körü körüne kullanmayın / önermeyin std::function. "Polimorfik" fonksiyonları (yani, bazı lambdalarda olduğu gibi durum içeriyor olsa bile, doğru imzası olan herhangi bir şeyi) saklama kabiliyeti için mükemmeldir, ancak bu, gerekli olmayan ek yükü de ekler. Bir işleve işaretçi POD'dur. A std::functiondeğil.
Matthew

2
@Matthew Adil olmak gerekirse, Adrian işaretçiyi işlevine dinamik olarak ayırmayı ve bir tür silme ile işaret etmeyi soruyor void*, bu nedenle bu soru bağlamında std::functiontam olarak aradıkları gibi görünüyor. SPD'nin işlev işaretleyicilerinin genel olarak işten çıkarılmasının uygun olmadığını kabul ediyorum.
eerorika

Yanıtlar:


27

İşlev işaretçileri nesne işaretçileri olmasa da, "bazı türlerin işlevlerini gösteren işaretçi" yine de bir nesne tipidir [basic.types] / 8 . Böylece, işlev işaretçileri kendileri nesnelerdir, sadece işaret ettikleri şey değildir.

Böylece, yeni bir ifade ile işlev işaretçi türü bir nesne oluşturabilirsiniz emin olabilirsiniz…


9

çünkü (işlev işaretçileri) bir geçersiz * işaretçide saklanamazlar.

Aslında, bir işlev işaretçisini bir olarak depolamak void*koşullu olarak desteklenir. Bu, dil uygulamasına bağlı olarak depolanabileceği veya kaydedilemeyeceği anlamına gelir. Dil uygulaması dinamik yüklemeyi destekliyorsa, void*muhtemelen işlev işaretçisi dönüştürme desteklenir. GCC, Clang ve MSVC'nin hepsi bunu destekler:

reinterpret_cast<void*>(&function);

İşaretçiye yeni bir işaretçi tahsis etmek yasal mı?

Elbette. İşlev işaretçileri de dahil olmak üzere tüm işaretçiler nesnedir ve tüm nesneler dinamik olarak atanabilir.

Ayrıca, işlev işaretçisi için sonuçtaki işaretçi düz bir veri işaretçisi gibi davranır

İşlev işaretçisi bir nesnedir. Bir işlev işaretçisi sadece "olarak davranır" işaretçi ama olan bir nesne için bir işaretçi.

Ben void * saklamak ve static_cast tarafından void * alabilirsiniz. Bu davranış Standart tarafından garanti ediliyor mu?

İşaretçiden boşluğa ve işaretçiden nesneye dönüştürmeye izin verilir, evet. Ve gidiş-dönüş dönüşümünün orijinal işaretçiyi vermesi garanti edilir.


Teşekkürler. Ama sonra işlev işaretçisi void * (veya tam tersi) dönüştürmek için, reinterpret_cast kullanmanız gerekiyor, değil mi?
Adrian

1
@Adrian Evet. Bir örnek ekledim.
eerorika

Muhtemelen bir istisna isteyen varsa: dos orta bellek modeli + yer paylaşımları. İşlev işaretçileri orta modeldeki veri işaretçilerinden daha büyüktür ve yeterince denerseniz eklentileri elde etmek için kaplamalar kullanılabilir.
Joshua
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.