我有一个接受指针向量的函数f
。函数f
完成后,这些指针不再有效。注意,没有必要更改向量本身,我只是想鼓励调用者在调用f
之后不使用指针。 f
有三种可能的签名:
移动签名
void f(vector<void*> &&v); // because the pointers in v are no longer valid.
// This signature also allows me to have f call clear() on v.
const签名
void f(const vector<void*> &v); // because the pointers in v are no longer valid,
// but we don't have to change the vector v.
指针签名
void f(vector<void*> *v); // The functino modifies v in a predictable way
// (it clears it). A pointer is used instead of a reference so that
// calls to the function will have a '&' which clearly shows to the reader
// that this function modifies its argument. '*' is different from '&&' since '&&'
// may imply "do not use v, but it is unknown how it will be modified" while
// '*' implies a clear semantic for how v is changed.
在C ++ 11中使用哪个签名更具惯用性?
答案 0 :(得分:2)
怎么样
void f(vector<void*> v);
使用它:
vector<void*> myVec = /*...*/;
f(std::move(myVec));
如果f
逻辑上需要向量的所有权,这是惯用的方式。它允许调用者决定是将向量移动还是复制到f
。
如果调用者实际上希望f
修改他的向量(因此向量实际上是一个输入/输出参数),那么这并不适合你的需要。然而,输入/输出参数很糟糕。函数应该将输入作为参数并将输出作为返回值返回。这就是上帝的意图。
答案 1 :(得分:2)
如果您真的想使用类型系统执行此操作,则始终可以使用您自己的类型对额外信息进行编码。
template<class T>
struct invalidates_contained_pointers;
template<class T>
invalidates_contained_pointers<T>* contents_will_be_invalidated(T* ptr) {
return reinterpret_cast<invalidates_contained_pointers<T>*>(ptr);
}
void f(invalidates_contained_pointers<vector<void*>> *v){
auto pv = reinterpret_cast<vector<void*> *>(v);
// ...
}
f(contents_will_be_invalidated(&vec));
类似的方法可用于参考。
答案 2 :(得分:1)
简短的回答:没有办法做到这一点。唯一的官方&#39;是相反的:是一个签名,它承诺函数f(..)
不会改变它的参数:const
关键字。
通常一个人坚持以下内容:
不修改其参数的函数要么将其参数作为值复制获取,要么使用const
明确标记其参数
由非const引用传递的参数,移动或指向非const对象的参数应该被读作&#34;这个参数很可能被被调用函数f(...)
修改&#34;
答案 3 :(得分:1)
正如其他人所说的那样,类型系统不允许您在此函数调用之后指出类似“不要使用此数据”的内容。你可以做什么:
void f(vector<void*> &v)
{
// ... use v ...
v.clear(); // encourage callers not to use the pointers after the call
}
答案 4 :(得分:1)
f
应该清除向量,如果它正在删除指针(或释放它们处理的任何内容)。让调用者留下一个intederminate值向量是毫无意义的。
所以f
应该通过非const引用接受向量。是否要进行此左值引用或右值引用取决于您;但是左值版似乎更简单。
答案 5 :(得分:0)
在这三个中:vector<void*> *
需要左值来获取地址。 const vector<void*> &
允许传入左值或右值。vector<void*> &&
只允许传入rvalues。
根据您的问题,使用左值或右值调用函数是有意义的,因此const vector<void*> &
是显而易见的选择。
无法通过类型系统指示调用者应该停止使用包含的指针,并且您不应该尝试通过类型系统指示。通过文档说明。