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

C++共享智能指針shared_ptr的實(shí)現(xiàn)

 更新時(shí)間:2023年12月28日 10:17:50   作者:Liuuuu408  
在C++中沒有垃圾回收機(jī)制,必須自己釋放分配的內(nèi)存,否則就會造成內(nèi)存泄露,解決這個(gè)問題最有效的方法是使用智能指針,本文主要介紹了C++共享智能指針shared_ptr的實(shí)現(xiàn),感興趣的可以了解一下

共享智能指針

在C++中沒有垃圾回收機(jī)制,必須自己釋放分配的內(nèi)存,否則就會造成內(nèi)存泄露。解決這個(gè)問題最有效的方法是使用智能指針(smart pointer)。智能指針是存儲指向動態(tài)分配(堆)對象指針的類,用于生存期的控制,能夠確保在離開指針?biāo)谧饔糜驎r(shí),自動地銷毀動態(tài)分配的對象,防止內(nèi)存泄露。智能指針的核心實(shí)現(xiàn)技術(shù)是引用計(jì)數(shù),每使用它一次,內(nèi)部引用計(jì)數(shù)加1,每析構(gòu)一次內(nèi)部的引用計(jì)數(shù)減1,減為0時(shí),刪除所指向的堆內(nèi)存。

C++11中提供了三種智能指針,使用這些智能指針時(shí)需要引用頭文件:

  • std::shared_ptr:共享的智能指針
  • std::unique_ptr:獨(dú)占的智能指針
  • std::weak_ptr:弱引用的智能指針,它不共享指針,不能操作資源,是用來監(jiān)視shared_ptr的。

1.shared_ptr的初始化

共享智能指針是指多個(gè)智能指針可以同時(shí)管理同一塊有效的內(nèi)存,共享智能指針shared_ptr 是一個(gè)模板類,如果要進(jìn)行初始化有三種方式:通過構(gòu)造函數(shù)、std::make_shared輔助函數(shù)以及reset方法。共享智能指針對象初始化完畢之后就指向了要管理的那塊堆內(nèi)存,如果想要查看當(dāng)前有多少個(gè)智能指針同時(shí)管理著這塊內(nèi)存可以使用共享智能指針提供的一個(gè)成員函數(shù)use_count,函數(shù)原型如下:

// 管理當(dāng)前對象的 shared_ptr 實(shí)例數(shù)量,或若無被管理對象則為 0。
long use_count() const noexcept;

1.1 通過構(gòu)造函數(shù)初始化

// shared_ptr<T> 類模板中,提供了多種實(shí)用的構(gòu)造函數(shù), 語法格式如下:
std::shared_ptr<T> 智能指針名字(創(chuàng)建堆內(nèi)存);

測試代碼如下:

#include <iostream>
#include <memory>
using namespace std;

int main()
{
    // 使用智能指針管理一塊 int 型的堆內(nèi)存
    shared_ptr<int> ptr1(new int(520));
    cout << "ptr1管理的內(nèi)存引用計(jì)數(shù): " << ptr1.use_count() << endl;
    // 使用智能指針管理一塊字符數(shù)組對應(yīng)的堆內(nèi)存
    shared_ptr<char> ptr2(new char[12]);
    cout << "ptr2管理的內(nèi)存引用計(jì)數(shù): " << ptr2.use_count() << endl;
    // 創(chuàng)建智能指針對象, 不管理任何內(nèi)存
    shared_ptr<int> ptr3;
    cout << "ptr3管理的內(nèi)存引用計(jì)數(shù): " << ptr3.use_count() << endl;
    // 創(chuàng)建智能指針對象, 初始化為空
    shared_ptr<int> ptr4(nullptr);
    cout << "ptr4管理的內(nèi)存引用計(jì)數(shù): " << ptr4.use_count() << endl;

    return 0;
}

測試代碼輸出的結(jié)果如下:

ptr1管理的內(nèi)存引用計(jì)數(shù): 1
ptr2管理的內(nèi)存引用計(jì)數(shù): 1
ptr3管理的內(nèi)存引用計(jì)數(shù): 0
ptr4管理的內(nèi)存引用計(jì)數(shù): 0

如果智能指針被初始化了一塊有效內(nèi)存,那么這塊內(nèi)存的引用計(jì)數(shù)+1,如果智能指針沒有被初始化或者被初始化為nullptr空指針,引用計(jì)數(shù)不會+1。另外,不要使用一個(gè)原始指針初始化多個(gè)shared_ptr。

int *p = new int;
shared_ptr<int> p1(p);
shared_ptr<int> p2(p);		// error, 編譯不會報(bào)錯(cuò), 運(yùn)行會出錯(cuò)

1.2 通過拷貝和移動構(gòu)造函數(shù)初始化

當(dāng)一個(gè)智能指針被初始化之后,就可以通過這個(gè)智能指針初始化其他新對象。在創(chuàng)建新對象的時(shí)候,對應(yīng)的拷貝構(gòu)造函數(shù)或者移動構(gòu)造函數(shù)就被自動調(diào)用了。

void test02() {
    // 使用智能指針管理一塊 int 型的堆內(nèi)存, 內(nèi)部引用計(jì)數(shù)為 1
    shared_ptr<int> ptr1(new int(520));
    cout << "ptr1管理的內(nèi)存引用計(jì)數(shù): " << ptr1.use_count() << endl;
    //調(diào)用拷貝構(gòu)造函數(shù)
    shared_ptr<int> ptr2(ptr1);
    cout << "ptr2管理的內(nèi)存引用計(jì)數(shù): " << ptr2.use_count() << endl;
    shared_ptr<int> ptr3 = ptr1;
    cout << "ptr3管理的內(nèi)存引用計(jì)數(shù): " << ptr3.use_count() << endl;
    //調(diào)用移動構(gòu)造函數(shù)
    shared_ptr<int> ptr4(std::move(ptr1));
    cout << "ptr4管理的內(nèi)存引用計(jì)數(shù): " << ptr4.use_count() << endl;
    std::shared_ptr<int> ptr5 = std::move(ptr2);
    cout << "ptr5管理的內(nèi)存引用計(jì)數(shù): " << ptr5.use_count() << endl;
}

測試程序輸入的結(jié)果:

ptr1管理的內(nèi)存引用計(jì)數(shù): 1
ptr2管理的內(nèi)存引用計(jì)數(shù): 2
ptr3管理的內(nèi)存引用計(jì)數(shù): 3
ptr4管理的內(nèi)存引用計(jì)數(shù): 3
ptr5管理的內(nèi)存引用計(jì)數(shù): 3

如果使用拷貝的方式初始化共享智能指針對象,這兩個(gè)對象會同時(shí)管理同一塊堆內(nèi)存,堆內(nèi)存對應(yīng)的引用計(jì)數(shù)也會增加;如果使用移動的方式初始智能指針對象,只是轉(zhuǎn)讓了內(nèi)存的所有權(quán),管理內(nèi)存的對象并不會增加,因此內(nèi)存的引用計(jì)數(shù)不會變化。

1.3 通過std::make_shared初始化

通過C++提供的std::make_shared() 就可以完成內(nèi)存對象的創(chuàng)建并將其初始化給智能指針,函數(shù)源碼如下:

template<class T, class... Args>
shared_ptr<T> make_shared(Args&&... args) {
    return std::allocate_shared<T>(std::allocator<T>(), std::forward<Args>(args)...);
}

這個(gè)函數(shù)模板使用了可變模板參數(shù)(variadic templates)和完美轉(zhuǎn)發(fā)(perfect forwarding)的特性。它接受一個(gè)類型 T 和任意數(shù)量的參數(shù)(Args),然后調(diào)用 std::allocate_shared 來完成共享指針的初始化和對象的構(gòu)造。

可變模板參數(shù)是指函數(shù)模板的參數(shù)數(shù)量是可變的。在std::make_shared的情況下,它允許我們以任意數(shù)量的參數(shù)初始化對象。

舉例來說,假設(shè)有一個(gè)類 MyClass:

class MyClass {
public:
    MyClass(int a, double b, const std::string& c) {
        // 構(gòu)造函數(shù)的實(shí)現(xiàn)
    }
};

可以使用 std::make_shared 來創(chuàng)建一個(gè) shared_ptr 并調(diào)用 MyClass 的構(gòu)造函數(shù):

#include <memory>
#include <string>

int main() {
    auto mySharedPtr = std::make_shared<MyClass>(42, 3.14, "Hello");
    // 使用 mySharedPtr
    return 0;
}

在這個(gè)例子中,MyClass 有一個(gè)帶有三個(gè)參數(shù)的構(gòu)造函數(shù),而 std::make_shared 允許你提供這三個(gè)參數(shù),以便在分配內(nèi)存時(shí)調(diào)用構(gòu)造函數(shù)進(jìn)行對象初始化??勺兡0鍏?shù)的使用使得 std::make_shared 能夠處理任意數(shù)量的構(gòu)造函數(shù)參數(shù)。

測試代碼如下:

#include <iostream>
#include <string>
#include <memory>
using namespace std;

class Test
{
public:
    Test()
    {
        cout << "construct Test..." << endl;
    }
    Test(int x)
    {
        cout << "construct Test, x = " << x << endl;
    }
    Test(string str)
    {
        cout << "construct Test, str = " << str << endl;
    }
    ~Test()
    {
        cout << "destruct Test ..." << endl;
    }
};

int main()
{
    // 使用智能指針管理一塊 int 型的堆內(nèi)存, 內(nèi)部引用計(jì)數(shù)為 1
    shared_ptr<int> ptr1 = make_shared<int>(520);
    cout << "ptr1管理的內(nèi)存引用計(jì)數(shù): " << ptr1.use_count() << endl;

    shared_ptr<Test> ptr2 = make_shared<Test>();
    cout << "ptr2管理的內(nèi)存引用計(jì)數(shù): " << ptr2.use_count() << endl;

    shared_ptr<Test> ptr3 = make_shared<Test>(520);
    cout << "ptr3管理的內(nèi)存引用計(jì)數(shù): " << ptr3.use_count() << endl;

    shared_ptr<Test> ptr4 = make_shared<Test>("我是要成為海賊王的男人!!!");
    cout << "ptr4管理的內(nèi)存引用計(jì)數(shù): " << ptr4.use_count() << endl;
    return 0;
}

測試代碼輸出:

ptr1管理的內(nèi)存引用計(jì)數(shù): 1
construct Test...
ptr2管理的內(nèi)存引用計(jì)數(shù): 1
construct Test, x = 520
ptr3管理的內(nèi)存引用計(jì)數(shù): 1
construct Test, str = 我是要成為海賊王的男人!!!
ptr4管理的內(nèi)存引用計(jì)數(shù): 1
destruct Test ...
destruct Test ...
destruct Test ...

使用std::make_shared()模板函數(shù)可以完成內(nèi)存地址的創(chuàng)建,并將最終得到的內(nèi)存地址傳遞給共享智能指針對象管理。如果申請的內(nèi)存是普通類型,通過函數(shù)的()可完成地址的初始化,如果要創(chuàng)建一個(gè)類對象,函數(shù)的()內(nèi)部需要指定構(gòu)造對象需要的參數(shù),也就是類構(gòu)造函數(shù)的參數(shù)。

1.4 通過reset方法初始化

共享智能指針類提供的std::shared_ptr::reset方法函數(shù)原型如下:

void reset() noexcept;

template< class Y >
void reset( Y* ptr );

template< class Y, class Deleter >
void reset( Y* ptr, Deleter d );

template< class Y, class Deleter, class Alloc >
void reset( Y* ptr, Deleter d, Alloc alloc );
  • ptr:指向要取得所有權(quán)的對象的指針
  • d:自定義的刪除器(deleter)
  • aloc:自定義的分配器

其中最常見的是不帶任何參數(shù)的形式和帶一個(gè)指針參數(shù)的形式。

不帶參數(shù)的reset

template<class Y>
void reset();

這個(gè)版本的 reset 將 shared_ptr 置為空,即它不再擁有任何對象。如果此時(shí) shared_ptr 是最后一個(gè)擁有某個(gè)對象的智能指針,它會調(diào)用對象的析構(gòu)函數(shù)來釋放資源。

std::shared_ptr<int> ptr = std::make_shared<int>(42);
ptr.reset();  // ptr 現(xiàn)在為空,且釋放了之前的對象

帶指針參數(shù)的reset

template<class Y>
void reset(Y* ptr);

這個(gè)版本的 reset 會替換 shared_ptr 當(dāng)前所管理的對象,并且使用參數(shù) ptr 所指向的對象。如果此時(shí) shared_ptr 是最后一個(gè)擁有某個(gè)對象的智能指針,它會調(diào)用原對象的析構(gòu)函數(shù)來釋放資源,然后開始管理新的對象。

std::shared_ptr<int> ptr = std::make_shared<int>(42);
ptr.reset(new int(10));  // ptr 不再指向之前的對象,而是指向一個(gè)新的 int 對象

帶指針和自定義刪除器的 reset

template<class Y, class Deleter>
void reset(Y* ptr, Deleter deleter);

這個(gè)版本的 reset 允許你指定一個(gè)自定義的刪除器(deleter),該刪除器將在 shared_ptr 管理的對象銷毀時(shí)被調(diào)用。這允許你使用 shared_ptr 管理通過非默認(rèn)方式分配的資源。

std::shared_ptr<int> ptr(new int, [](int* p) { delete p; });
ptr.reset(new int, [](int* p) { delete[] p; });

帶指針、自定義刪除器和分配器的 reset

template<class Y, class Deleter, class Alloc>
void reset(Y* ptr, Deleter deleter, Alloc alloc);

這個(gè)版本的 reset 允許你指定自定義的刪除器和分配器。通常情況下,std::shared_ptr 使用默認(rèn)分配器 std::allocator 和默認(rèn)刪除器 delete

std::shared_ptr<int> ptr(new int, [](int* p) { delete p; }, std::allocator<int>());

來看一下這個(gè)例子:

#include <iostream>
#include <string>
#include <memory>
using namespace std;

int main()
{
    // 使用智能指針管理一塊 int 型的堆內(nèi)存, 內(nèi)部引用計(jì)數(shù)為 1
    shared_ptr<int> ptr1 = make_shared<int>(520);
    shared_ptr<int> ptr2 = ptr1;
    shared_ptr<int> ptr3 = ptr1;
    shared_ptr<int> ptr4 = ptr1;
    cout << "ptr1管理的內(nèi)存引用計(jì)數(shù): " << ptr1.use_count() << endl; // 4
    cout << "ptr2管理的內(nèi)存引用計(jì)數(shù): " << ptr2.use_count() << endl; // 4
    cout << "ptr3管理的內(nèi)存引用計(jì)數(shù): " << ptr3.use_count() << endl; // 4
    cout << "ptr4管理的內(nèi)存引用計(jì)數(shù): " << ptr4.use_count() << endl; // 4

    ptr4.reset();
    cout << "ptr4管理的內(nèi)存引用計(jì)數(shù): " << ptr4.use_count() << endl; // 0
    ptr4.reset(new int(250));
    cout << "ptr1管理的內(nèi)存引用計(jì)數(shù): " << ptr1.use_count() << endl; // 3
    cout << "ptr2管理的內(nèi)存引用計(jì)數(shù): " << ptr2.use_count() << endl; // 3
    cout << "ptr3管理的內(nèi)存引用計(jì)數(shù): " << ptr3.use_count() << endl; // 3
    cout << "ptr4管理的內(nèi)存引用計(jì)數(shù): " << ptr4.use_count() << endl; // 1

    return 0;
}

對于一個(gè)未初始化的共享智能指針,可以通過reset方法來初始化,當(dāng)智能指針中有值的時(shí)候,調(diào)用reset會使引用計(jì)數(shù)減1。

1.5 獲取原始指針

通過智能指針可以管理一個(gè)普通變量或者對象的地址,此時(shí)原始地址就不可見了。當(dāng)我們想要修改變量或者對象中的值的時(shí)候,就需要從智能指針對象中先取出數(shù)據(jù)的原始內(nèi)存的地址再操作,解決方案是調(diào)用共享智能指針類提供的get()方法,其函數(shù)原型如下:

T* get() const noexcept;

測試代碼如下:

#include <iostream>
#include <string>
#include <memory>
using namespace std;

int main()
{
    int len = 128;
    shared_ptr<char> ptr(new char[len]);
    // 得到指針的原始地址
    char* add = ptr.get();
    fill(ptr.get(), ptr.get() + len, '\0');
    const char* source = "我愛cpp";
    copy(source, source + strlen(source) + 1, ptr.get());
    cout << "string: " << ptr.get() << endl;

    shared_ptr<int> p(new int);
    *p = 100;
    cout << *p.get() << "  " << *p << endl; // 100 100

    return 0;
}

2.指定刪除器

當(dāng)智能指針管理的內(nèi)存對應(yīng)的引用計(jì)數(shù)變?yōu)?的時(shí)候,這塊內(nèi)存就會被智能指針析構(gòu)掉了。另外,我們在初始化智能指針的時(shí)候也可以自己指定刪除動作,這個(gè)刪除操作對應(yīng)的函數(shù)被稱之為刪除器,這個(gè)刪除器函數(shù)本質(zhì)是一個(gè)回調(diào)函數(shù),我們只需要進(jìn)行實(shí)現(xiàn),其調(diào)用是由智能指針完成的。

#include <iostream>
#include <memory>
using namespace std;

// 自定義刪除器函數(shù),釋放int型內(nèi)存
void deleteIntPtr(int* p)
{
    delete p;
    cout << "int 型內(nèi)存被釋放了...";
}

int main()
{
    shared_ptr<int> ptr(new int(250), deleteIntPtr);
    return 0;
}

刪除器函數(shù)也可以是lambda表達(dá)式,因此代碼也可以寫成下面這樣:

int main()
{
    shared_ptr<int> ptr(new int(250), [](int* p) {delete p; });
    return 0;
}

在上面的代碼中,lambda表達(dá)式的參數(shù)就是智能指針管理的內(nèi)存的地址,有了這個(gè)地址之后函數(shù)體內(nèi)部就可以完成刪除操作了。

管理動態(tài)數(shù)組

在C++11中使用shared_ptr管理動態(tài)數(shù)組時(shí),需要指定刪除器,因?yàn)閟td::shared_ptr的默認(rèn)刪除器不支持?jǐn)?shù)組對象,具體的處理代碼如下:

int main()
{
    shared_ptr<int> ptr(new int[10], [](int* p) {delete[]p; });
    return 0;
}

在刪除數(shù)組內(nèi)存時(shí),除了自己編寫刪除器,也可以使用C++提供的std::default_delete()函數(shù)作為刪除器,這個(gè)函數(shù)內(nèi)部的刪除功能也是通過調(diào)用delete來實(shí)現(xiàn)的,要釋放什么類型的內(nèi)存就將模板類型T指定為什么類型即可。具體處理代碼如下:

int main()
{
    shared_ptr<int> ptr(new int[10], default_delete<int[]>());
    return 0;
}

另外,我們還可以自己封裝一個(gè)make_shared_array方法來讓shared_ptr支持?jǐn)?shù)組,代碼如下:

#include <iostream>
#include <memory>
using namespace std;

template <typename T>
shared_ptr<T> make_share_array(size_t size)
{
    // 返回匿名對象
    return shared_ptr<T>(new T[size], default_delete<T[]>());
}

int main()
{
    shared_ptr<int> ptr1 = make_share_array<int>(10);
    cout << ptr1.use_count() << endl;
    shared_ptr<char> ptr2 = make_share_array<char>(128);
    cout << ptr2.use_count() << endl;
    return 0;
}

資源的所有權(quán)轉(zhuǎn)移

另一方面: 指定刪除器也用于資源的所有權(quán)轉(zhuǎn)移

刪除器允許你將資源的所有權(quán)轉(zhuǎn)移給智能指針。這對于使用自定義釋放邏輯的資源管理類很有幫助,因?yàn)槟憧梢詫①Y源的釋放責(zé)任委托給智能指針。

class CustomResource {
public:
    CustomResource(int* data) : data_(data) {}
    void release() { delete[] data_; }

private:
    int* data_;
};

// 將自定義資源類的釋放函數(shù)作為刪除器
std::shared_ptr<CustomResource> customPtr(new CustomResource(new int[10]), [](CustomResource* resource) {
    resource->release();
    delete resource;
});

到此這篇關(guān)于C++共享智能指針shared_ptr的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++ shared_ptr內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • C++進(jìn)一步認(rèn)識類與對象

    C++進(jìn)一步認(rèn)識類與對象

    類是創(chuàng)建對象的模板,一個(gè)類可以創(chuàng)建多個(gè)對象,每個(gè)對象都是類類型的一個(gè)變量;創(chuàng)建對象的過程也叫類的實(shí)例化。每個(gè)對象都是類的一個(gè)具體實(shí)例(Instance),擁有類的成員變量和成員函數(shù)
    2021-10-10
  • 深入C++浮點(diǎn)數(shù)無效值定義與判定的解決辦法

    深入C++浮點(diǎn)數(shù)無效值定義與判定的解決辦法

    本篇文章是對C++中浮點(diǎn)數(shù)無效值定義與判定進(jìn)行了介紹,需要的朋友參考下
    2013-05-05
  • 用c++實(shí)現(xiàn)x的y次冪的代碼

    用c++實(shí)現(xiàn)x的y次冪的代碼

    以下實(shí)例是對使用c++實(shí)現(xiàn)x的y次冪的解決方法進(jìn)行了介紹。需要的朋友參考下
    2013-05-05
  • 冒泡算法的改進(jìn)具體實(shí)現(xiàn)

    冒泡算法的改進(jìn)具體實(shí)現(xiàn)

    這篇文章主要介紹了冒泡算法的改進(jìn)具體實(shí)現(xiàn),有需要的朋友可以參考一下
    2013-12-12
  • c++primer類詳解

    c++primer類詳解

    今天小編就為大家分享一篇關(guān)于C++Primer中變量和基本類型的文章,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2021-09-09
  • 基于Matlab實(shí)現(xiàn)繪制3D足球的示例代碼

    基于Matlab實(shí)現(xiàn)繪制3D足球的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用Matlab實(shí)現(xiàn)繪制3D足球,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Matlab有一定幫助,需要的可以參考一下
    2022-11-11
  • C++中成員函數(shù)和友元函數(shù)的使用及區(qū)別詳解

    C++中成員函數(shù)和友元函數(shù)的使用及區(qū)別詳解

    大家好,本篇文章主要講的是C++中成員函數(shù)和友元函數(shù)的使用及區(qū)別詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • C語言一級指針二級指針和三級指針區(qū)別及使用詳解

    C語言一級指針二級指針和三級指針區(qū)別及使用詳解

    這篇文章主要為大家介紹了C語言一級指針二級指針和三級指針,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • C++回調(diào)函數(shù)的理解和使用教程

    C++回調(diào)函數(shù)的理解和使用教程

    這篇文章主要給大家介紹了關(guān)于C++回調(diào)函數(shù)的理解和使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • C++常用的11種設(shè)計(jì)模式解釋及示例代碼詳解

    C++常用的11種設(shè)計(jì)模式解釋及示例代碼詳解

    c++常用的設(shè)計(jì)模式包括單例模式、工廠模式、抽象工廠模式、適配器模式、裝飾者模式、代理模式、外觀模式、橋接模式、組合模式、享元模式、觀察者模式和命令模式等,這篇文章主要介紹了C++常用的11種設(shè)計(jì)模式解釋及示例,需要的朋友可以參考下
    2023-02-02

最新評論

隆德县| 彰化市| 晋州市| 灌南县| 汉阴县| 高州市| 安宁市| 宣武区| 青铜峡市| 望奎县| 图们市| 庆安县| 迁安市| 盘山县| 东乡族自治县| 永顺县| 绥中县| 东兴市| 宁夏| 闸北区| 泽库县| 黄梅县| 温州市| 湖口县| 霞浦县| 平陆县| 祁门县| 射洪县| 张北县| 蚌埠市| 措美县| 交口县| 密云县| 隆子县| 泗洪县| 增城市| 江永县| 三门峡市| 进贤县| 嵊泗县| 广西|