最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++的智能指針的原理解析

 更新時間:2026年05月19日 09:17:13   作者:青瓦夢滋  
本文主要介紹了C++中智能指針的使用及其解決內(nèi)存泄漏問題的方法,傳統(tǒng)的指針需要手動釋放內(nèi)存,容易導致內(nèi)存泄漏,而智能指針可以在生命周期結(jié)束時自動釋放資源,解決內(nèi)存泄漏問題,感興趣的朋友跟隨小編一起看看吧

由于C++沒有GC(垃圾回收機制),所有動態(tài)開辟的空間都需要我們手動釋放,這就會導致

  1. 忘記釋放
  2. 異常安全問題

不管哪種情況,都會導致內(nèi)存泄漏

 下面先來簡單復習一下異常安全問題

int Div() throw(invalid_argument)
{
	int a, b;
	cin >> a >> b;
	if (b == 0)
		throw invalid_argument("除0錯誤");
	return a / b;
}
void fun()
{
	int* p = new int;
	cout << Div() << endl;
	delete p;
}
int main()
{
	try
	{
		fun();
	}
	catch (exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

此時,如果在Div中拋出異常,就會跳過fun()函數(shù)最后的 delete p; 語句,從而導致內(nèi)存泄漏,這就是異常安全問題

 那么異常是怎么解決這個問題的呢?

int Div() throw(invalid_argument)
{
	int a, b;
	cin >> a >> b;
	if (b == 0)
		throw invalid_argument("除0錯誤");
	return a / b;
}
void fun()
{
	int* p = new int;
	try
	{
		cout << Div() << endl;
	}
	catch (...)//若拋出異常,這里會先捕獲異常,釋放空間后再重新拋出
	{
		delete p;
		throw;
	}
	delete p;
}
int main()
{
	try
	{
		fun();
	}
	catch (exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

使用了異常的重新拋出,先在內(nèi)層的catch語句中完成空間的釋放,再將該異常重新拋出交給外面的catch處理

但這樣的解決方法會涌現(xiàn)很多問題

例如,當我們開辟了多個空間,如果DIv拋異常,就需要先將這3個空間都釋放掉 

void fun()
{
	int* p1 = new int;
	int* p2 = new int;
	int* p3 = new int;
	try
	{
		cout << Div() << endl;
	}
	catch (...)
	{
		delete p1;
		delete p2;
		delete p3;
		throw;
	}
	delete p1;
	delete p2;
	delete p3;
}

但是開辟空間如果失敗了也是會拋異常的,如果這里的new拋異常怎么辦?并且還需要清楚是哪個變量的new拋出的異常

有讀者可能會想,給每個new都放在一個單獨的try塊中,再給每個try寫一個單獨的catch,不就可以解決了嗎?

首先,如果new語句在try塊內(nèi),那么在try塊外的delete語句就會找不到p1,p2,p3

再者,就算可以找到,那怎么判斷哪個new拋的異常,從而不去delete對應對象,又是個問題

這時候,就要請出本文的主角——智能指針

智能指針的原理

智能指針其實是一個類 

template <class T>
class SmartPtr
{
public:
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{}
	~SmartPtr()
	{
		if(_ptr)
        {
			delete _ptr;
            _ptr = nullptr;
        }    
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
private:
	T* _ptr;
};

在該類中,定義了構(gòu)造、析構(gòu)、*重載、->重載,而類中存的是一個指針

 現(xiàn)在我如果把一個原生指針存進去,就不需要我手動釋放了

int* p = new int;
SmartPtr<int> sp(p);

因為類在生命周期結(jié)束后會自動調(diào)用析構(gòu)函數(shù),而現(xiàn)在原生指針交給智能指針管理后,當原生指針的生命周期結(jié)束時,智能指針的生命周期也會結(jié)束,此時調(diào)用該類的析構(gòu)函數(shù),就可以釋放該原生指針的空間

*重載 和->重載是為了讓智能指針可以更好的模擬原生指針的行為

 既然智能指針可以完全模擬原生指針的行為了,那其實我們可以這么定義

SmartPtr<int> sp(new int);//或SmartPtr<int> sp = new int;//這里調(diào)用的也是構(gòu)造

有了智能指針,再發(fā)生異常安全問題時,就無需重新拋出異常了

int Div() throw(invalid_argument)
{
	int a, b;
	cin >> a >> b;
	if (b == 0)
		throw invalid_argument("除0錯誤");
	return a / b;
}
void fun()
{
	SmartPtr<int> sp = new int;
	cout << Div() << endl;
}
int main()
{
	try
	{
		fun();
	}
	catch (exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

此時如果Div函數(shù)內(nèi)部拋出異常,那么在異常拋出后會先執(zhí)行SmartPtr的析構(gòu)函數(shù),再執(zhí)行catch塊中的代碼

即使沒有拋異常,在fun函數(shù)執(zhí)行完后,也會調(diào)用SmartPtr的析構(gòu)函數(shù),相當于將指針托管給了智能指針

RAII

 智能指針的這種做法,就被叫做RAII(Resource Acquisition Is Initialization),它是一種利用對象生命周期來控制程序資源(如內(nèi)存、文件句柄、網(wǎng)絡連接、互斥量等等)的簡單技術(shù)。

詳細點解釋,就是在對象構(gòu)造時獲取資源,接著控制對資源的訪問使之在對象的生命周期內(nèi)始終保持有效,最后在對象析構(gòu)的時候釋放資源。借此,我們實際上把管理一份資源的責任托管給了一個對象。這種做法有兩大好處:

  • 不需要顯式地釋放資源。
  • 采用這種方式,對象所需的資源在其生命期內(nèi)始終保持有效。

需要注意的是,RAII是一種托管資源的思想,智能指針是依靠RAII實現(xiàn)的,除了智能指針之外,還有例如unique_lock/lock_gurad等等也是依托RAII實現(xiàn)的

智能指針的問題

當我們想將一個智能指針的值賦給另一個智能指針時,問題就出現(xiàn)了

SmartPtr<int> sp1 = new int;
SmartPtr<int> sp2 = sp1;//調(diào)用默認拷貝構(gòu)造

 此時會報錯

這是因為sp1和sp2中指針的地址是同一個,那么就會導致兩次釋放,和淺拷貝問題很像

針對這個問題,C++一共給出了三種解決方案

  • C++98:auto_ptr     管理權(quán)轉(zhuǎn)移  (了解)
  • C++11:unique_ptr  防拷貝  
  • C++11:shared_ptr  引用計數(shù)的共享拷貝  循環(huán)拷貝問題需要用weak_ptr解決

auto_ptr

auto_ptr是C++98中自帶的類,因此如果要實現(xiàn)自己的auto_ptr,需要將它放在一個命名空間中

namespace valkyrie
{
	template <class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* ptr)
			:_ptr(ptr)
		{}
		auto_ptr(auto_ptr<T>& ap)//管理權(quán)轉(zhuǎn)移,將ap存的地址轉(zhuǎn)移給*this
			:_ptr(ap._ptr)
		{
			ap._ptr = nullptr;
		}
		auto_ptr& operator=(auto_ptr<T>& ap)//依舊管理權(quán)轉(zhuǎn)移,不過需要先將原先this中的空間釋放
		{
			if (this != &ap)
			{
				if (_ptr)
					delete _ptr;
				_ptr = ap._ptr;
				ap._ptr = nullptr;
			}
			return *this;
		}
		~auto_ptr()
		{
			if (_ptr)
			{
				delete _ptr;
				_ptr = nullptr;
			}
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};
}

 大部分代碼都和之前我們實現(xiàn)的SmartPtr一樣,唯一區(qū)別在于拷貝構(gòu)造和賦值重載顯式定義了

 該拷貝構(gòu)造的核心在于原先ap1管理的空間,交給ap2管理,而ap1再置空

賦值重載也一樣,但需要先將原先存的空間釋放掉

那此時如果再想 *ap2 = 1;  就會引發(fā)空指針解引用問題,而崩潰

這也是C++早期的設計缺陷,一般都是公司明令禁止使用的

unique_ptr

 unique_ptr 是C++11新引入的智能指針,它對于拷貝構(gòu)造和賦值重載的做法是直接禁止,已達到防拷貝的目的

namespace valkyrie
{
    template <class T>
	class unique_ptr
	{
	public:
		unique_ptr(unique_ptr<T>&) = delete;//刪除該類的拷貝構(gòu)造
		unique_ptr<T>& operator=(unique_ptr<T>&) = delete;//刪除該類的賦值重載
		unique_ptr(T* ptr)
			:_ptr(ptr)
		{
		}
		~unique_ptr()
		{
			if (_ptr)
			{
				delete _ptr;
				_ptr = nullptr;
			}
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};
}

這樣在我們嘗試調(diào)用拷貝構(gòu)造或賦值重載時,就會報錯

unique_ptr的思路簡單粗暴,是比較推薦實用的,但缺陷也很明顯:如果有需要拷貝的場景,它就沒法使用

shared_ptr

 shared_ptr 也是C++11引入的智能指針,它和 unique_ptr 的區(qū)別在于它可以拷貝構(gòu)造和賦值

 shared_ptr 的思路是通過引用計數(shù)的方式來實現(xiàn)多個 shared_ptr 對象之間共享資源。

每個資源都對應一個計數(shù)指針,用來記錄該份資源被幾個對象共享。

拷貝構(gòu)造: 

為什么計數(shù)的變量是指針?因為只有指針才可以實現(xiàn)在多個對象中同步變化

 賦值重載時,需要先判斷原先存儲的空間需不需要釋放,再執(zhí)行如同拷貝構(gòu)造一樣的操作

此時就是直接釋放的情況,下面再演示一下不需要釋放的情況

namespace valkyrie
{	
    template <class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr)
			:_ptr(ptr)
			,_pcount(new int(1))
		{}
		shared_ptr(const shared_ptr<T>& sp)//拷貝構(gòu)造,將指針和計數(shù)指針都拷貝給它,并將引用計數(shù)+1,表示又多一個托管這塊內(nèi)存的智能指針
			:_ptr(sp._ptr)
			,_pcount(sp._pcount)
		{
			(*_pcount)++;
		}
		shared_ptr<T>& operator=(shared_ptr<T>& sp)//賦值重載,先判斷原先該智能指針中的空間需不需要釋放(等于先調(diào)用了一次析構(gòu)函數(shù)),再執(zhí)行和拷貝構(gòu)造一樣的步驟
		{
			if (this != &sp)
			{
				if (--(*_pcount) == 0 && _ptr)
				{
					delete _ptr;
					_ptr = nullptr;
					delete _pcount;
					_pcount = nullptr;
				}
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				(*_pcount)++;
			}
			return *this;
		}
		~shared_ptr()
		{
				if (--(*_pcount) == 0 && _ptr)//先將引用計數(shù)-1,看看是否為0,如果為0,就代表沒有智能指針在托管這塊空間了,直接釋放;但如果不為0,就代表還有*pcount個智能指針在托管這塊空間,不能釋放
				{
					delete _ptr;
					_ptr = nullptr;
					delete _pcount;
					_pcount = nullptr;
				}
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
		int* _pcount;//引用計數(shù),用來統(tǒng)計目前有幾個智能指針在同時托管這塊空間
	};
}

shared_ptr的線程安全問題

當有多個線程用 shared_ptr 管理著同一份共享資源時,由于引用計數(shù)需要++(析構(gòu)時也需要--),因此就會有多個線程同時對一個引用計數(shù)++(--)而導致的數(shù)據(jù)不一致問題。

C++11的shared_ptr是線程安全的,下面簡單實現(xiàn)一下通過將引用計數(shù)包裝成 atomic 原子類型而實現(xiàn)的線程安全版本:

namespace val
{
    template<class T>
    class shared_ptr
    {
    public:
        shared_ptr(T* ptr)
        :_ptr(ptr)
        ,_count(new atomic<int>(1))
        {}
        shared_ptr(const shared_ptr<T>& sp)
        :_ptr(sp._ptr)
        ,_count(sp._count)
        {
            if(_count)
                (*_count)++;
        }
        shared_ptr<T>& operator=(shared_ptr sp)
        {
            //現(xiàn)代寫法,并且保證了線程安全
            if(this != &sp)
            {
                swap(_ptr,sp._ptr);
                swap(_count,sp._count);
            }
            return *this;
        }
        ~shared_ptr()
        {
            if(_count && --(*_count) == 0)
            {
                delete _ptr;
                delete _count;
            }
        }
        T& operator*()
        {
            return *_ptr;
        }
        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
        atomic<int>* _count;//將引用計數(shù)包裝成原子類型
    };
}

shared_ptr的循環(huán)引用問題

當shared_ptr托管的對象需要雙向依賴關系,例如雙向鏈表(next節(jié)點和prev節(jié)點),或樹的父子節(jié)點,就會因為引用計數(shù)無法歸零而導致內(nèi)存泄漏

例如下面這種情況:

template <class T>
struct ListNode
{
    T val;
    val::shared_ptr<ListNode> prev;
    val::shared_ptr<ListNode> next;
};
int main()
{
    val::shared_ptr<ListNode<int>> ln1(new ListNode<int>);
    val::shared_ptr<ListNode<int>> ln2(new ListNode<int>);
    cout << ln1.getcnt()/*獲取當前智能指針的引用計數(shù)*/ << endl << ln2.getcnt() << endl;
    ln1->next = ln2;
    ln2->prev = ln1;
    cout << ln1.getcnt() << endl << ln2.getcnt() << endl;
    return 0;
}

在這段代碼里,ln1內(nèi)托管的對象由ln1和ln2->prev同時托管,ln2內(nèi)托管的對象由ln2和ln1->next同時托管,那么ln1和ln2的引用計數(shù)都為2

當程序結(jié)束,ln1和ln2調(diào)用析構(gòu)函數(shù)后,各自都把引用計數(shù)減到1各自都以為還有別的shared_ptr在托管該資源(next和prev),所以都沒釋放,這就造成了內(nèi)存泄漏

要想解決,就需要把雙向依賴關系里的指針不再引用計數(shù)++,因此C++11還有一個 weak_ptr ,它不是智能指針,而是專門用于解決shared_ptr循環(huán)引用問題的指針,將shread_ptr賦給weak_ptr時,引用計數(shù)不會++,而只是像個普通指針一樣

template <class T>
class weak_ptr
{
public:
    weak_ptr() = default; // 默認構(gòu)造函數(shù)
    weak_ptr(const shared_ptr<T> &sp)
        : _ptr(sp.operator->())
    {
    }
    weak_ptr<T> &operator=(shared_ptr<T> sp)//參數(shù)是shared_ptr
    {
        _ptr = sp.operator->(); // 獲取sp._ptr
        return *this;
    }
    ~weak_ptr()
    {
        _ptr = nullptr;//不釋放,只置空
    }
    T &operator*()
    {
        return *_ptr;
    }
    T *operator->()
    {
        return _ptr;
    }
private:
    T *_ptr;
};

只要將雙向依賴關系中的資源交給weak_ptr管理,就解決了循環(huán)引用問題

template <class T>
struct ListNode
{
    T val;
    val::weak_ptr<ListNode> prev;
    val::weak_ptr<ListNode> next;
};
int main()
{
    val::shared_ptr<ListNode<int>> ln1(new ListNode<int>);
    val::shared_ptr<ListNode<int>> ln2(new ListNode<int>);
    cout << ln1.getcnt()/*獲取當前智能指針的引用計數(shù)*/ << endl << ln2.getcnt() << endl;
    ln1->next = ln2;
    ln2->prev = ln1;
    cout << ln1.getcnt() << endl << ln2.getcnt() << endl;
    return 0;
}

定制刪除器

在C++11之前,也就是C++98后,智能指針只有auto_ptr,這之間的十幾年由于官方一直沒有作為,一個名為 boost 的第三方庫就出現(xiàn)了,它給出了 scoped_ptr shared_ptr 、 weak_ptr ,并且除了智能指針也有非常多的實現(xiàn),后續(xù)C++11的 unique_ptr 、 shared_ptr 、 weak_ptr 就是參考 boost 庫實現(xiàn)的

boost庫中除了有scoped_ptr和shared_ptr,還有 scoped_array shared_array 。由于智能指針默認的釋放資源的方式都是delete,如果是以new []創(chuàng)建的數(shù)組,就不能用delete了,因此scoped_array/shared_array是boost中專門給new []準備的智能指針,它們的釋放資源的方式是delete[]

C++11沒有引入xxx_array的智能指針,它靠定制刪除器來實現(xiàn)(也是借鑒的boost庫)

如果直接將new []的數(shù)據(jù)交給智能指針管理,在析構(gòu)時會報錯

class A
{
public:
    ~A()
    {
        cout << "~A()" << endl;
    }
private:
    int a;
    int b;
};
int main()
{
    shared_ptr<A>(new A[10]);
    return 0;
}

此時可以定義一個仿函數(shù)。讓智能指針在釋放資源時自動調(diào)用仿函數(shù)內(nèi)的 operator() 

template<class T>
struct deleteArr
{
    void operator()(T* v)
    {
        delete[] v;
    }
};
int main()
{
    shared_ptr<A>(new A[10],deleteArr<A>());
    return 0;
}

這就叫做定制刪除器

除了new,new[]之外,malloc/fopen等等需要回收的類型都可以使用定制刪除器交給智能指針管理

class A
{
public:
    ~A()
    {
        cout << "~A()" << endl;
    }
private:
    int a;
    int b;
};
template<class T>
struct deleteArr
{
    void operator()(T* v)
    {
        delete[] v;
    }
};
template<class T>
struct deleteFree
{
    void operator()(T* v)
    {
        free(v);
    }
};
struct deleteFclose
{
    void operator()(FILE* v)
    {
        fclose(v);
    }
};
int main()
{
    shared_ptr<A>(new A[10],deleteArr<A>());
    shared_ptr<A>((A*)malloc(sizeof(A)),deleteFree<A>());
    shared_ptr<FILE>(fopen("tmp.txt","w"),deleteFclose());
    return 0;
}

需要注意的是,上面只是為了演示定制刪除器的用法,若真需要用智能指針管理數(shù)組,應該用unique_ptr,它有operator[]重載

lock_guard/unique_lock(RAII機制托管鎖)

平時有加鎖解鎖的操作時,如果中間的某個函數(shù)拋出異常,就會出現(xiàn)死鎖問題,需要通過捕獲重新拋出的方式對其解鎖

mtx.lock();
try
{
    f();
}
catch(...)
{
    mtx.unlock();//捕獲重新拋出
    throw;
}
mtx.unlock();

C++11中,專門為鎖的RAII寫了兩個對象, lock_guard unique_lock ,它們可以在出生命周期時自動釋放鎖

lcok_guard就是純粹的RAII的管理鎖,構(gòu)造時加鎖,析構(gòu)時解鎖,該對象只有構(gòu)造和析構(gòu)兩個接口

template<class lock>
class Lock_Guard
{
public:
    Lock_Guard(lock& lk)//引用傳參,這樣傳過去的鎖也是同一個
    :_lk(lk)
    {
        //_lk = lk;
        _lk.lock();
    }
    ~Lock_Guard()
    {
        _lk.unlock();
    }
    Lock_Guard(const Lock_Guard<lock>&) = delete;//lock_guard不允許拷貝
    Lock_Guard<lock>& operator=(Lock_Guard<lock>) = delete;
private:
    lock& _lk;//引用類型
};
mutex mtx;
void fun()
{
    Lock_Guard<mutex> lg(mtx);
    throw(string("拋出異常"));
}

需要注意的是lock_guard是不支持拷貝

 unique_lock 除了可以像lock_guard一樣RAII,還可以自己加鎖或解鎖

void fun()
{
    unique_lock<mutex> lg(mtx);
    throw(string("拋出異常"));
    lg.unlock();
    //...其他工作
    lg.lock();
    //...
}

到此這篇關于【語法】C++的智能指針的文章就介紹到這了,更多相關C++的智能指針內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 如何統(tǒng)計在一篇文章中某個單詞出現(xiàn)了幾次,以及第一次出現(xiàn)的位置

    如何統(tǒng)計在一篇文章中某個單詞出現(xiàn)了幾次,以及第一次出現(xiàn)的位置

    本文的主要內(nèi)容就是統(tǒng)計某個單詞在一篇文章中出現(xiàn)了幾次,以及第一次出現(xiàn)的位置,需要的朋友可以參考下
    2015-08-08
  • C++兩種素數(shù)判定方法

    C++兩種素數(shù)判定方法

    這篇文章主要介紹了C++如何判斷一個數(shù)是不是素數(shù),提供了兩種方法具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • QT的QWebEngineView類知識點詳細介紹

    QT的QWebEngineView類知識點詳細介紹

    QWebEngineView是Qt框架中的組件,基于Chromium內(nèi)核,支持HTML5、CSS3、JavaScript等Web技術(shù),適用于嵌入網(wǎng)頁內(nèi)容到Qt應用程序,它提供了豐富的接口如加載、導航、與JavaScript交互等,并支持信號槽機制處理各種網(wǎng)頁事件,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-10-10
  • c++實現(xiàn)十進制轉(zhuǎn)換成16進制示例

    c++實現(xiàn)十進制轉(zhuǎn)換成16進制示例

    這篇文章主要介紹了c++實現(xiàn)十進制轉(zhuǎn)換成16進制示例,需要的朋友可以參考下
    2014-05-05
  • C語言中的內(nèi)存管理之掌握動態(tài)分配的技巧(最新推薦)

    C語言中的內(nèi)存管理之掌握動態(tài)分配的技巧(最新推薦)

    在C語言編程中,內(nèi)存管理是一項至關重要的技能,它直接關系到程序的性能和穩(wěn)定性,特別是在處理大型數(shù)據(jù)集或需要靈活內(nèi)存布局的場景下,本文將深入探討C語言中的動態(tài)內(nèi)存分配技巧,幫助開發(fā)者更好地掌握這一核心技能
    2025-03-03
  • C++使用alsa庫實現(xiàn)播放聲音文件

    C++使用alsa庫實現(xiàn)播放聲音文件

    這篇文章主要為大家詳細介紹了Linux系統(tǒng)上C++如何使用alsa庫播放聲音文件,文中示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-04-04
  • C++應用Eigen庫對應實現(xiàn)matlab中部分函數(shù)問題

    C++應用Eigen庫對應實現(xiàn)matlab中部分函數(shù)問題

    這篇文章主要介紹了C++應用Eigen庫對應實現(xiàn)matlab中部分函數(shù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 快速入門的一些C\C++書籍

    快速入門的一些C\C++書籍

    這篇文章為大家精心推薦了一些快速入門的一些C\C++書籍,希望大家可以喜歡,對這門語言可以產(chǎn)生興趣,需要的朋友可以參考下
    2015-12-12
  • VC++ 獲取系統(tǒng)時間的方法匯總

    VC++ 獲取系統(tǒng)時間的方法匯總

    本文給大家匯總介紹了5種VC++中獲取系統(tǒng)時間的方法,十分的簡單實用,有需要的小伙伴可以參考下。
    2015-07-07
  • QT中QDockWidget控件的使用小結(jié)

    QT中QDockWidget控件的使用小結(jié)

    QDockWidget類提供了一個小部件,可以停靠在QMainWindow中,也可以作為桌面上的頂級窗口浮動,本文主要介紹了QT中QDockWidget控件的使用小結(jié),感興趣的可以了解一下
    2024-01-01

最新評論

宁国市| 万山特区| 汶上县| 土默特右旗| 舞钢市| 涿鹿县| 盐亭县| 梅州市| 周至县| 萨嘎县| 屏东市| 兴业县| 延寿县| 锦州市| 宁波市| 峡江县| 七台河市| 东港市| 通江县| 桑植县| 昔阳县| 襄汾县| 共和县| 班戈县| 沐川县| 麻栗坡县| 西乌珠穆沁旗| 栾城县| 武陟县| 鹤庆县| 兴宁市| 惠东县| 灵丘县| 巴东县| 阜康市| 濉溪县| 伊宁县| 淄博市| 尉犁县| 赤城县| 驻马店市|