我试图理解rvalue引用并移动C++ 11的语义.
这些示例之间有什么区别,哪些不会执行矢量复制?
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> &&rval_ref = return_vector();
Run Code Online (Sandbox Code Playgroud)
std::vector<int>&& return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
Run Code Online (Sandbox Code Playgroud)
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
Run Code Online (Sandbox Code Playgroud) 我试图std::thread用一个不带参数和返回的成员函数构造一个void.我无法弄清楚任何有效的语法 - 编译器无论如何都会抱怨.实现的正确方法是什么,spawn()以便返回std::thread执行的test()?
#include <thread>
class blub {
void test() {
}
public:
std::thread spawn() {
return { test };
}
};
Run Code Online (Sandbox Code Playgroud) 在我们通过引用传递参数时,是否可以为函数的参数提供默认值.在C++中
例如,当我尝试声明一个函数时:
virtual const ULONG Write(ULONG &State = 0, bool sequence = true);
Run Code Online (Sandbox Code Playgroud)
当我这样做时,它给出了一个错误:
错误C2440:'default argument':无法从'const int'转换为'unsigned long&'不是'const'的引用不能绑定到非左值
在这种情况下
struct Foo {};
Foo meh() {
return std::move(Foo());
}
Run Code Online (Sandbox Code Playgroud)
我很确定移动是不必要的,因为新创建的Foo将是一个xvalue.
但在这种情况下呢?
struct Foo {};
Foo meh() {
Foo foo;
//do something, but knowing that foo can safely be disposed of
//but does the compiler necessarily know it?
//we may have references/pointers to foo. how could the compiler know?
return std::move(foo); //so here the move is needed, right?
}
Run Code Online (Sandbox Code Playgroud)
我认为需要采取行动吗?
请考虑此代码.我已经多次看过这种类型的代码了.words是一个本地向量.如何从函数中返回它?我们可以保证它不会死吗?
std::vector<std::string> read_file(const std::string& path)
{
std::ifstream file("E:\\names.txt");
if (!file.is_open())
{
std::cerr << "Unable to open file" << "\n";
std::exit(-1);
}
std::vector<string> words;//this vector will be returned
std::string token;
while (std::getline(file, token, ','))
{
words.push_back(token);
}
return words;
}
Run Code Online (Sandbox Code Playgroud) 在对另一个问题的评论中, Jonathan Wakely回应了我的陈述:
您永远不需要显式移动局部变量函数返回值.这是隐含的举动
- >
...永远不要说永远......如果局部变量与返回类型的类型不同,则需要显式移动,例如
std::unique_ptr<base> f() { auto p = std::make_unique<derived>(); p->foo(); return p; },但如果类型相同,则可能会移动...
所以有时我们可能不得不在返回时移动局部变量.
这个例子
std::unique_ptr<base> f() {
auto p = std::make_unique<derived>();
p->foo();
return p;
}
Run Code Online (Sandbox Code Playgroud)
很好,因为它给出了编译错误
> prog.cpp:10:14: error: cannot convert ‘p’ from type
> ‘std::unique_ptr<derived>’ to type ‘std::unique_ptr<derived>&&’
Run Code Online (Sandbox Code Playgroud)
但我想知道是否有一个很好的机会来检测这一般 - 这是这里的语言规则或unique_ptr ??
请考虑以下代码:
class StringTokenizer
{
private:
char m_delimiter;
std::istringstream m_string;
public:
explicit StringTokenizer(const std::string& str, char delimiter)
: m_string(str)
, m_delimiter(delimiter)
{
}
template <class Container>
operator Container ()
{
Container container;
for (std::string token; std::getline(m_string, token, m_delimiter); )
{
container.insert(container.end(), token);
}
return container;
}
};
Run Code Online (Sandbox Code Playgroud)
这是用法:
vector<string> tmp = StringTokenizer("123 456", ' '); //Please note the implicit conversion
Run Code Online (Sandbox Code Playgroud)
调试时发生以下情况(使用VS2013):
在return转换运算符声明中
container由移动构造的新向量container 被破坏了功能返回后:
tmp 由复制构造函数构造我的问题是为什么不是tmp由移动构造函数构造的?
据我所知,函数返回类型是rvalue,应该移动.
如果我编写一个在本地实例化对象然后按值返回的工厂方法,打算利用NRVO(根据这里的一些答案:c ++ 11返回值优化或移动?),指针/引用将是本地对象指向分配了方法返回值的对象?
Object ObjectBuilder::BuildObject( void )
{
Object obj;
//this->ObjectReference = obj; //Disregard this
//OR
this->ObjectPtr = &obj;
return obj;
}
Run Code Online (Sandbox Code Playgroud)
正在使用:
ObjectBuilder builder;
Object newObject = builder.BuildObject();
Run Code Online (Sandbox Code Playgroud)
builder.ObjectPtr是否引用newObject?
标准不需要编译器执行返回值优化(RVO),但是从C ++ 11开始,必须移动结果。
看来,这可能会将UB引入到/破坏代码中,这在C ++ 98中是有效的。
例如:
#include <vector>
#include <iostream>
typedef std::vector<int> Vec;
struct Manager{
Vec& vec;
Manager(Vec& vec_): vec(vec_){}
~Manager(){
//vec[0]=42; for UB
vec.at(0)=42;
}
};
Vec create(){
Vec a(1,21);
Manager m(a);
return a;
}
int main(){
std::cout<<create().at(0)<<std::endl;
}
Run Code Online (Sandbox Code Playgroud)
当使用gcc(或与此相关的clang)进行编译时(为了简化示例,-O2 -fno-inline -fno-elide-constructors我正在使用std::vector这些build-option。如果没有这些选项以及手工类和更复杂的create功能,则可能会触发相同的行为)对于C ++ 98(-std=c++98)一切正常:
return a;触发复制构造函数,它保持a原样。m称为(必须在a被销毁之前发生,因为它m是在之后构造的a)。a在析构函数中访问是没有问题的。a函数称为。结果与预期的一样:21已打印(此处为live)。 …
我有一个功能,需要对给定的元素进行排序。原始矢量一定不能更改,因此我需要该矢量的浅表副本。由于我不需要复制元素本身,因为它们只能被读取,所以我决定制作一个指针向量。目前,我有一个简单的循环来填充矢量,但是我想知道是否存在内置/标准解决方案,甚至可能更快。
void calcFindMinLeftAndSort(std::vector<Location>& locationsComplete, std::vector<Location*>& locationsSorted) {
// ...
// copy data in new array, to keep the original untouched
locationsSorted.reserve(locationsComplete.size());
// looking for locationsSorted.assign(&elements)
// yes, I could use for each instead
for (size_t i = 0; i < locationsComplete.size(); i++)
locationsSorted.emplace_back(&locationsComplete[i]);
// sort
std::sort(locationsSorted.begin(), locationsSorted.end(), compare);
}
Run Code Online (Sandbox Code Playgroud)
附加信息:locationsComplete向量按特定顺序排序,不得更改。该矢量在应用程序运行期间不会改变。排序后的locationSorted向量被另一个函数使用了一次(可以在同一函数中使用,但这种方式看起来更清晰)。返回下一个函数的结果后,locationsSorted向量将退役。因此,它可以看作是寿命很短的临时载体。