[英]When should I use references in C++?
我一直在編寫C ++編程,我開始懷疑規則使用引用應盡可能應用於任何地方。
與這個相關的SO帖子不同,我對一種不同的東西感興趣。
根據我的經驗,參考/指針混合會混淆你的代碼:
std::vector<Foo *> &x = get_from_somewhere(); // OK? reference as return value
some_func_pass_by_ref(x); // OK reference argument and reference variable
some_func_by_pointer(x[4]); // OK pointer arg, pointer value
some_func_pass_elem_by_ref(*x[5]); // BAD: pointer value, reference argument
some_func_that_requires_vec_ptr(&x); // BAD: reference value, pointer argument
一種選擇是,以取代&
與* const
像Foo &
與Foo * const
void some_func_by_ref(const std::vector<Foo * const> * const); // BAD: verbose!
這樣至少走遍了。 而且我重寫函數頭文件已經不見了,因為所有參數都是指針......代價是使用const
而不是指針算法(主要是&
和*
)來污染代碼。
我想知道在可能的規則下如何以及何時應用使用引用 。
考慮:
提高可讀性
*
將Foo*
轉換為Foo&
,反之亦然 * const
注意:我想要的一件事是每當我打算將元素放入STL容器時使用指針(參見boost :: ref)
我認為這不是C ++ 03特有的東西,但如果它們可以被反向移植到C ++ 03(即:NRVO而不是移動語義),那么C ++ 11解決方案就可以了。
我什么時候應該在C ++中使用引用?
當你需要處理像對象本身這樣的變量時(大多數情況下你不明確需要指針而不想取得對象的所有權)。
我想知道在可能的規則下如何以及何時應用使用引用 。
盡可能 ,除非您需要 :
Bjarne Stroustrup在他的書中指出他引入了對該語言的引用,因為需要在不制作對象副本的情況下調用運算符(這意味着“通過指針”)並且他需要尊重類似於按值調用的語法(這意味着“不是通過指針”)(因此參考文獻誕生了)。
簡而言之,您應該盡可能少地使用指針:
const &
接收參數 std::shared_ptr
, std::unique_ptr
, your_raii_pointer_class_here
- 而不是(原始)指針 .get()
獲取指針以獲取原始指針。 我想到的一件事是每當我打算將元素放入STL容器時使用指針(或者我可以擺脫它嗎?)
您可以使用Boost指針容器庫 。
恕我直言,因為原始指針很危險,因為所有權和破壞責任很快就不清楚了。 因此,圍繞概念的多個封裝( smart_ptr
, auto_ptr
, unique_ptr
,...)。 首先,考慮在容器中使用這樣的封裝而不是原始指針。
其次,為什么需要將指針放在容器中? 我的意思是,它們意味着包含完整的物體; 畢竟,他們有一個allocator作為模板參數,用於精確的內存分配。 大多數情況下,你需要指針,因為你有一個OO方法大量使用多態。 你應該重新考慮這種方法。 例如,您可以替換:
struct Animal {virtual std::string operator()() = 0;};
struct Dog : Animal {std::string operator()() {return "woof";}};
struct Cat : Animal {std::string operator()() {return "miaow";}};
// can not have a vector<Animal>
通過類似的方式,使用Boost.Variant :
struct Dog {std::string operator()() {return "woof";}};
struct Cat {std::string operator()() {return "miaow";}};
typedef boost::variant<Dog, Cat> Animal;
// can have a vector<Animal>
這樣,當您添加新動物時,您不會繼承任何內容,只需將其添加到變體即可。
使用Boost.Fusion時 ,您也可以考慮使用更復雜但更通用的東西:
struct Dog {std::string talk; Dog() : talk("wook"){}};
struct Cat {std::string talk; Cat() : talk("miaow"){}};
BOOST_FUSION_ADAPT_STRUCT(Dog, (std::string, talk))
BOOST_FUSION_ADAPT_STRUCT(Cat, (std::string, talk))
typedef boost::fusion::vector<std::string> Animal;
int main()
{
vector<Animal> animals;
animals.push_back(Dog());
animals.push_back(Cat());
using boost::fusion::at;
using boost::mpl::int_;
for(auto a : animals)
{
cout << at<int_<0>>(a) << endl;
}
}
這樣你甚至不需要修改像變種這樣的集合,也不需要修改動物上的算法,你只需要提供一個與所用算法先決條件相匹配的FUSION_ADAPT。 兩個版本(變體和融合)都允許您定義正交對象組,這是繼承樹無法做到的有用事情。
處理此問題的方法似乎合理:
我選擇使用Handle / Body Idiom方法,因為它在隱藏底層實現和所有權語義的同時提供指針自動復制/分配行為。 它還可以作為一種編譯時防火牆,減少頭文件包含。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.