c++函數參數和返回值

来源:https://www.cnblogs.com/zijian-yang/archive/2023/05/19/17415864.html
-Advertisement-
Play Games

- [c++函數參數和返回值](#c函數參數和返回值) - [函數存儲位置](#函數存儲位置) - [函數參數入棧順序](#函數參數入棧順序) - [初始化列表](#初始化列表) - [函數的返回值](#函數的返回值) - [用參數引用來返回](#用參數引用來返回) - [返回一個參數指針](#返回 ...


c++函數參數和返回值

c++一直以來是一個關註效率的代碼,這樣關於函數的參數傳遞和返回值的接收,是重中之重。下文提供了一些個人的見解。

函數存儲位置

函數參數在編譯期展開,目前各平臺的編譯期均有不同。

名稱 存儲位置
函數名稱和邏輯 代碼段存儲
函數參數和返回值 棧中或者寄存器(64位會有6個寄存器使用)
new malloc 的變數

函數參數入棧順序

微軟有幾種編譯期屬性,用來定義函數參數的順序和堆棧。

關鍵字 堆棧清理 參數傳遞
__cdecl 調用方 在堆棧上按相反順序推送參數(從右到左)
__clrcall 不適用 按順序將參數載入到 CLR 表達式堆棧上(從左到右)。
__stdcall 被調用方 在堆棧上按相反順序推送參數(從右到左)
__fastcall 被調用方 存儲在寄存器中,然後在堆棧上推送
__thiscall 被調用方 在堆棧上推送;存儲在 ECX 中的 this 指針
__vectorcall 被調用方 存儲在寄存器中,然後按相反順序在堆棧上推送(從右到左)

所以直接在函數參數上,調用表達式和函數來回去值的話,非常危險

初始化列表

class Init1
{
public:

    void Print()
    {
        std::cout << a << std::endl;
        std::cout << b << std::endl;
        std::cout << c << std::endl;
    }

    int c, a, b;
};

A這個類,可以通過 A a{1,2,3}; 來初始化對象。
看著很美好,但是有幾個問題需要註意。
參數是的入棧順序是跟著類的屬性的順序一致, 當前是 c, a, b;

int i = 0;
Init1 a = {i++, i++, i++};
a.Print();

當我如此調用的時候,得到的返回值是 1 2 0
i++的執行順序是從左到右,跟函數調用順序無關。 另外不能有 構造函數

	class Init1
	{
	public:
		Init1(int ia, int ib, int ic)
		{
			std::cout << "construct" << std::endl;
			a = ia;
			b = ib;
			c = ic;
		}
		Init1(const Init1& other)
		{
			std::cout << "copy " << std::endl;
			a = other.a;
			b = other.b;
			c = other.c;
		}

		void Print()
		{
			std::cout << a << std::endl;
			std::cout << b << std::endl;
			std::cout << c << std::endl;
		}

		int c, a, b;
	};

當我添加了構造函數的時候。 用下麵代碼測試。會得到兩種結果

void Test_InitilizeList()
{
	int i = 0;
	//Init1 a = { i++, i++, i++ }; // 0 1 2 
	Init1 a(i++, i++, i++); // 2 1 0 
	a.Print();
}

函數的返回值

函數返回值的聲明周期在函數體內。

用參數引用來返回

class Result
{
public:
int result;
};
void GetResult(Result& result) ...

優點:

  • 效率最高,因為返回值的對象在函數體外構造,可以一直套用, 可以一處構造,一直使用。
  • 安全,可以定義對象,並不用new或者malloc, 沒有野指針困擾。
    缺點:
  • 代碼可讀性低,不夠優美
  • 無法返回nullptr. 一般在 Result 中定義一個; 用來表示一個空對象。
  • 容易賦值到一個臨時對象中,當調用GetResult({1}) 會賦值到一個 臨時的 Result 對象中,拿不到返回值。正常來說也不會這樣做。

返回一個參數指針

class Result
{
public:
int result;
};
Result* GetResult() ...

優點:

  • 簡潔明瞭
  • 參數傳遞快速
    缺點:
  • 指針如果在 函數內 static 需要考慮多線程。 如果是 new 出來的,多次調用效率不高
  • 指針無法重覆使用,(可以用 std::share_ptr 增加對象池來解決問題。但會引入新的複雜度。)
  • 需要考慮釋放的問題

返回一個對象

class Result
{
public:
int result;
};
Result GetResult() ...

優點:

  • 沒有記憶體泄露的風險
  • 簡潔明瞭
    缺點:
  • 但有個別編譯期優化選項問題,會導致一次構造兩次拷貝, 第一次是函數體內對象向返回值拷貝,第二次是 返回值拷貝給外面接收參數的。
  • 開啟編譯期優化選項,並且是 在 return Result 的時候構造返回對象,才能優化。

總結

一般如果是 簡單結構體,用 返回一個臨時對象的方式解決。
如果使用 返回一個參數指針,一般改成返回一個id,用一個manager來管理記憶體機制。或者 共用記憶體,記憶體池來解決記憶體泄露後續的問題
用 參數引用來返回的話,一般會這麼定義 int GetResult(Result& result) 函數返回值,用來返回狀態碼,真正的數據,放到 result 中。

函數的幾種變體

inline 函數

  • inline 函數是內聯函數,是編譯期優化的一種手段,一般是直接展開到調用者代碼里,減少函數堆棧的開銷。
  • inline 標識只是建議,並不是一定開啟內聯。
  • 函數比較複雜或者遞歸有可能編譯期不展開。
  • dll 導出的時候,可以不用加導出標識,會直接導出到目標處。
  • inline 在msvc的平臺,只要實現頭文件中,加不加內聯是一樣的. (警告頂級調到最高/Wall, 不加inline標識的函數會提示,未使用的內聯函數將被刪除。)
  • inline 函數比全局函數更快,但是全局函數無法定義在頭文件中(會報多重定義函數。)所以一般用class 包一層 static inline 函數,用來寫工具類。

函數對象

class A {
public :
    int value;  
    int operator() (int val) {
        return value + val;
    }
}

上述代碼是一個函數對象,重載operator()得到一個函數對象。
int a = A{10}(1) 會返回11, 顯示構造了一個A{value=10}的對象,然後調用重載函數operator(), 返回 10 + 1 = 11
上述代碼因為是在頭文件實現的,所以編譯期會自動把operator()函數當成inline函數,執行效率很高。

lambda 函數

lambda 其實就是一個函數對象,會在編譯期展開成一個函數對象體。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • **本文為千鋒資深前端教學老師帶來的【JavaScript全解析】系列,文章內含豐富的代碼案例及配圖,從0到1講解JavaScript相關知識點,致力於教會每一個人學會JS!** **文末有本文重點總結,可以收藏慢慢看\~ 更多技術類內容,主頁關註一波!** # ES6函數中參數的預設值 給函數的形 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 loading的展示和取消可以說是每個前端對介面的時候都要關心的一個問題。這篇文章將要幫你解決的就是如何結合axios更加簡潔的處理loading展示與取消的邏輯。 首先在我們平時處理業務的時候loading一般分為三種:按鈕loadin ...
  • 馬上就要520了,也許你能用到這款《文生圖》工具!把字藏在圖裡,發給女神,大膽去表白吧~,文末附源碼喲!預覽地址:https://dombro.site/tools#/text-image ...
  • 當定義和調用函數時,JavaScript 函數對象會自動具有一些特定的屬性,以下是一些常見的屬性和方法。 1. arguments : arguments 是一個類數組對象,它包含了函數調用時傳遞的參數。它允許你在函數內部訪問傳遞給函數的參數列表,即使在函數定義時未明確聲明這些參數。可以通過索引訪問 ...
  • 關於JWT,可以說是分散式系統下的一個利器,我在我的很多項目實踐中,認證系統的第一選擇都是JWT。它的優勢會讓你欲罷不能,就像你領優惠券一樣。 ...
  • 有很多人問過我,學習開源項目消息推送平臺austin需要有什麼基礎,我往往會回答:**有`SpringBoot`基礎就夠了**。 我在幾年前總結過從零學習`Java`的路線,現在看來也沒有很過時: - `Java`基礎:流程式控制制-->面向對象(包括語法)-->集合-->`IO`流-->異常-->多線 ...
  • # C++ 如何快速實現一個容器的迭代器 ## 引言 C++的標準庫中的容器都會提供迭代器,如果一個容器滿足forward_range,那麼這個容器一般會提供以下成員類型和函數: - iterator - const_iterator - begin - end - begin - cend 如果該 ...
  • pom引入:有MP了就不要再引入mybatis了,會出bug的 ```xml com.baomidou mybatis-plus-boot-starter 3.5.3.1 com.baomidou mybatis-plus-generator 3.5.3.1 junit junit 4.13.2 ` ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...