簡體   English   中英

如何在沒有臨時變量的情況下將指針傳遞給整數?

[英]How to pass a pointer to an integer without a temporary variable?

在我過去的許多語言中,有一種方法可以傳遞一個整數常量/文字作為參考,以避免不必要地創建極其短暫的變量到函數。 一個很好的例子是setsockopt調用的重用變量。 例如

int reuseVal = 1;    
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuseVal, sizeof (reuseVal));

某些語言允許您執行以下操作

setsockopt(s, SOL_SOCKET, SO_REUSEADDR, %ref(1), sizeof (int));

C ++中是否有類似的方法?

C ++內置的東西沒有你想要的東西,但你自己很容易構建一個(為了清晰起見,額外的日志記錄):

template <typename T>
class holster
{
public:
    using value_type = T;

    template <typename... U>
    holster(U&&... args)
        : _val(std::forward<U>(args)...)
    {
        std::cout << "CTOR: holster" << std::endl;
    }

    ~holster()
    {
        std::cout << "DTOR: holster" << std::endl;
    }

    value_type* ptr() { return &_val; }

private:
    value_type _val;
};

這種類型的用法非常簡單:

struct thing
{
    thing()
    {
        std::cout << "CTOR: thing" << std::endl;
    }

    ~thing()
    {
        std::cout << "DTOR: thing" << std::endl;
    }
};

void foo(thing*)
{
    std::cout << "in foo" << std::endl;
}

int main()
{
    foo(holster<thing>().ptr());
    return 0;
}

要擴展回原始示例:

setsockopt(s, SOL_SOCKET, SO_REUSEADDR, holster<int>(1).ptr(), sizeof (int));

為什么這樣做? C ++生命周期的一個鮮為人知的特性是,在函數持續時間內,為傳遞給函數而創建的任何臨時函數都是生命周期延長的。 保證引用( holster::_val )在foo返回之前繼續存在,並且在評估下一個完整表達式之前將被正確銷毀(在本例中,在;之前)。

§6.6.7/ 4 [class.temporary]

當實現引入具有非平凡構造函數的類的臨時對象( [class.default.ctor][class.copy.ctor] )時,它應確保為臨時對象調用構造函數。 類似地,析構函數應該用一個非平凡的析構函數( [class.dtor] )來調用。 臨時對象作為評估全表達式( [intro.execution] )的最后一步被銷毀,該表達式(詞法上)包含創建它們的點。 即使該評估以拋出異常結束,也是如此。 銷毀臨時對象的值計算和副作用僅與完整表達相關聯,而不與任何特定子表達相關聯。

你不能直接這樣做。 在C中你可以使用復合文字(例如(int []){ 1 } ),但這在C ++中不可用。

但是,您可以編寫如下輔助函數:

template<typename T>
struct temp_holder {
    T data;
    explicit temp_holder(T x) : data(x) {}
    T *ptr() { return &data; }
    const T *ptr() const { return &data; }
};

template<typename T>
temp_holder<T> make_temporary(T x) {
    temp_holder<T> tmp(x);
    return tmp;
}

現在你可以這樣做:

setsockopt(s, SOL_SOCKET, SO_REUSEADDR, make_temporary(1).ptr(), sizeof (int));

在我使用g ++進行的測試中,在0以上的任何優化級別(即-O-O2-O3 )生成int reuseVal = 1 / &reuseVal版本的相同代碼。

如果您想避免必須定義新的類型和函數,可以稍微濫用標准庫:

#include <memory>

setsockopt(s, SOL_SOCKET, SO_REUSEADDR, std::make_unique<int>(1).get(), sizeof (int));

這種方法的缺點是它經歷了動態內存分配(加上(異常安全)釋放),因此它可能比自定義類型慢(或者只是聲明一個臨時變量)。

setsockopt()需要指向已分配變量的指針。 無論該變量是靜態分配還是動態分配,都無關緊要,只要它具有可在運行時獲得的可訪問內存地址,然后取消引用以訪問該地址處的數據即可。

您的原始代碼正是如此。 它宣布,在自動內存分配的局部變量(即調用線程的調用堆棧),然后使用該地址的&運營商來獲取變量的內存地址,並將該地址setsockopt() 事情並沒有那么簡單。

您給出的其他答案只是同一主題的更復雜的變體 - 為變量賦值,然后獲取該變量的地址。

為了節省聲明基本類型變量並用數據填充它的ALREADY EXTREMELY MINIMAL開銷,您可以使用在程序啟動時初始化一次並在需要時重用的全局變量在編譯時靜態執行該操作,例如:

const int cReuseAddrOn = 1;

void setReuseAddrOn(int s)
{
    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &cReuseAddrOn, sizeof (cReuseAddrOn));
} 

%ref(1)其他語言中的%ref(1)這樣的東西可能與此類似地實現,創建對臨時分配的變量或可重用的文字常量的引用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM