Fonksiyon Parametresinin Kullanılmayacağını Belirtmek

A &func(A &a, B &b, C c)
{
    // a ve b kullanılarak yapılan işlemler
}

Bu fonksiyonda c argümanını kullanmayacağımızı explicit bir şekilde belirtmenin bir yolu var mı? Direkt argümanı sil diyebilirsiniz ama inherited class'ların base class'ın virtual function'ını override ettiği durumlarda böyle birşey mümkün değil. Yoksa compiler’lar zaten burda optimizasyon yapar mı?

Parametrenin ismini yazmasanız?

A &func(A &a, B &b, C)

veya: https://jmmv.dev/2015/02/unused-parameters-in-c-and-c.html#tagging-unused-parameters-with-compiler-attributes

Optimizasyon yapıyor mu yapmıyor mu heralde compiler-spesifiktir, assembly’sine bakıp belki görebilirsiniz.

1 Beğeni

c parametresinin kullanilmayacagini belirtmenin yolu c parametresini kullanmamak.

Optimizer’larin bu kadar temel bir bilgiye yardimsiz erisip erisemeyecegini bilmiyorsan bu kadar teknik bir cevabi hak etmiyorsun kullanamazsin demektir.

Meraktan soruyorsan oku, dene, incele, kurcala.

Ihtiyactan soruyorsan kodun ve girdinin tamamini, kullanilan derleyiciyi, calisan platformu ve memnun olmadigin profiler ciktisini rica ediyoruz.


Edit: “Hak etmiyorsun” derken; cevabi verebilecek kadar teknik bilgiye sahip insanin cevabi vermek icin harcadigi sure, cevaptan alabilecegin “haa, optimize ediyormus” veya “haa, optimize etmiyormus” derslerine degmez.

1 Beğeni

Şu kod ile şu 4 farklı durumu test ettim:

  • Argüman Kullanılıyor
  • Argüman Kullanılıyor Ama Fonksiyona Etkisi Yok
  • Argüman Kullanılmıyor
  • Argüman Kullanılmıyor ve İsmi Belirtilmemiş
#include <iostream>
#include <cstdint>
#include <chrono>

struct LittleBoy {
    int64_t arr[10000];
};


class Base {
public:
    virtual int func(int, LittleBoy) = 0;
};


class ArgUsed : public Base {
public:
    int func(int number, LittleBoy littleBoy) override {
        littleBoy.arr[0] = 0;

        int sum{0};
        for (int i{0}; i < number; i++)
            sum += i;
        return sum;
    }
};


class ArgUsedButNoEffect : public Base {
public:
    int func(int number, LittleBoy littleBoy) override {
        littleBoy;

        int sum{0};
        for (int i{0}; i < number; i++)
            sum += i;
        return sum;
    }
};


class ArgUnused : public Base {
public:
    int func(int number, LittleBoy littleBoy) override {
        int sum{0};
        for (int i{0}; i < number; i++)
            sum += i;
        return sum;
    }
};


class ArgUnusedNameOmitted : public Base {
public:
    int func(int number, LittleBoy) override {
        int sum{0};
        for (int i{0}; i < number; i++)
            sum += i;
        return sum;
    }
};

class Benchmarker {
private:
    const std::chrono::time_point<std::chrono::high_resolution_clock> startedTimePoint_;

public:
    Benchmarker() : startedTimePoint_(std::chrono::high_resolution_clock::now()) {}

    ~Benchmarker() {
        auto stoppedTimePoint = std::chrono::high_resolution_clock::now();
        auto duration = stoppedTimePoint - startedTimePoint_;

        std::cout << "benchmark result: " << duration.count() << std::endl;
    }
};



int main() {
    LittleBoy littleBoy{};

    {
        ArgUsed instance;
        std::cout << "Function with Argument Used:" << std::endl;

        Benchmarker benchmarker;
        instance.func(1, littleBoy);
    }

    {
        ArgUsedButNoEffect instance;
        std::cout << "Function with Argument Used But Have No Effect:" << std::endl;

        Benchmarker benchmarker;
        instance.func(1, littleBoy);
    }

    {
        ArgUnused instance;
        std::cout << "Function with Argument Unused:" << std::endl;

        Benchmarker benchmarker;
        instance.func(1, littleBoy);
    }

    {
        ArgUnusedNameOmitted instance;
        std::cout << "Function with Argument Unsed and Argument Name Omitted:" << std::endl;

        Benchmarker benchmarker;
        instance.func(1, littleBoy);
    }

    return 0;
}

Kodu Ubuntu 20.04’de, g++ ile derledim. g++ sürümüm 9.3.0. Optimizasyon için compiler’a ayrı parametre vermedim. Sonuç:

toxide@toxide:~/dev/scrt/unused-args$ g++ main.cpp -o main
toxide@toxide:~/dev/scrt/unused-args$ ./main 
Function with Argument Used:
benchmark result: 80112
Function with Argument Used But Have No Effect:
benchmark result: 9318
Function with Argument Unused:
benchmark result: 8933
Function with Argument Unsed and Argument Name Omitted:
benchmark result: 9683

Sonuç:
g++ 9.3.0 kullanılarak varsayılan parametreler ile kod derlendiğinde optimizasyon yapılıyor.

Kod niye zaman olcuyor anlamadim. Parametrenin/argumanin kullanildigi ile kullanilmadigi durumlarda nasil bir sure farkli bekliyorsun?

Memory kullanimini olcup aradaki farkin tam 8k (veya bir kati) olmasini beklerdim ben. Hatta 8k hali hazirda yuvarlak bir sayi oldugu icin rastgele karsimiza cikabilir; 47k filan daha mantikli olabilir.

Bu arada zaman olcerken cagri sayisi olarak 1 veya belirli bir cagri sirasi kullanmaman lazim. Hatta ilk birkac cagriyi da gozardi etmek gerekir ama cagri sayisi yuksekse o zaman amortize olur zaten.

littleBoy kopyalanacağı için zaman farkı olacak eğer optimizasyon yapılmadı ise. Aklıma ilk zamanı ölçmek geldi sonuçta burda optimizasyon yapılıp yapılmadığını merak etmemin nedeni performans.

Bunu nasıl ölçebilirim? Çünkü kodu debug ederken optimizasyonların çoğu yapılmıyor. Düzgün bir karşılaştırma olur mu emin değilim.

Sanırım haklısınız. Tek bir kere çağırmak her zaman doğru sonucu vermeyebilir.

Hmm, bilemedim. Stack’ten paslanacagini varsayiyorsun. Standart bununla ilgili bir sey demiyor.

Bir seyin kopyalanacagindan emin olmanin tek yolu kopyalanmasini gerektiren bir kod yazmak. Su haliyle koddan silinebilir (ve muhtemelen siliniyor zaten).

Performansiyla ilgilendigin kodu yerinde test etmen lazim. Optimizasyona da tek bir sey olarak bakamazsin; burada gordugun gibi baska optimizasyonlar girebilir devreye.

Isletim sisteminin olcmek icin mekanizmalari mutlaka vardir. Bunun disinda profilerlarin ne oldugunu arastirmak isteyebilirsin. Release kodunu (optimize kodu) debug etmek daha zor, evet. Ama imkansiz degil; sonucta assembly kodu, elle yazdigin assembly kodunu debug ediyormus gibi davranabilirsin.

Burada da vermemis zaten; farkindayiz, degil mi?

1 Beğeni