我一直在编程C ++已经有一段时间了,我开始怀疑规则尽可能使用引用应该在任何地方应用。
与this related SO post不同,我对另一种事情感兴趣。
根据我的经验,参考/指针混合会弄乱你的代码:
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
而不是指针算法(主要是&
和*
)来污染代码。 / p>
我想知道 和
考虑:
提高可读性
*
将Foo*
转换为Foo&
,反之亦然* const
注意:我想到的一件事是每当我打算将元素放入STL容器时使用指针(参见boost :: ref)
我认为这不是C ++ 03特有的,但是如果它们可以被反向移植到C ++ 03(即:NRVO而不是移动语义),那么C ++ 11解决方案就没问题了。
答案 0 :(得分:7)
我什么时候应该在C ++中使用引用?
当你需要处理像对象本身这样的变量时(大多数情况下你没有明确需要指针而不想取得对象的所有权)。
我想知道如何以及何时应用尽可能使用引用规则。
尽可能,除非您需要:
Bjarne Stroustrup在他的书中指出,他引入了对该语言的引用,因为需要在不制作对象副本的情况下调用运算符(这意味着“通过指针”),并且他需要遵循类似于按值调用的语法(这意味着“不是通过指针”)(因此引用已经诞生)。
简而言之,你应该尽可能少地使用指针:
const &
std::shared_ptr
,std::unique_ptr
,your_raii_pointer_class_here
- 而不是(原始)指针.get()
获取指针以获取原始指针。我想到的一件事是每当我打算将元素放入STL容器时使用指针(或者我可以摆脱它吗?)
答案 1 :(得分:2)
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。两个版本(变体和融合)都允许您定义正交对象组,这是继承树无法做到的有用的事情。
答案 2 :(得分:0)
以下方法似乎对此有合理处理:
我选择使用Handle / Body Idiom方法,因为它在隐藏底层实现和所有权语义的同时提供指针自动复制/分配行为。它还可以作为一种编译时防火墙,减少头文件包含。