相关疑难解决方法(0)

快速将一个矢量复制到另一个矢量

我更喜欢两种方式:

void copyVecFast(const vec<int>& original)
{
  vector<int> newVec;
  newVec.reserve(original.size());
  copy(original.begin(),original.end(),back_inserter(newVec));
}

void copyVecFast(vec<int>& original)
{

  vector<int> newVec;
  newVec.swap(original); 
}
Run Code Online (Sandbox Code Playgroud)

你怎么做呢?

c++ algorithm stl

142
推荐指数
6
解决办法
32万
查看次数

在定位C++ 03时使用std :: basic_string <t>作为连续缓冲区是否合理?

我知道在C++ 03中,从技术上讲,std::basic_string模板不需要具有连续的内存.但是,我很好奇有多少实现存在于实际利用这种自由的现代编译器.例如,如果想要用来basic_string接收某些C API的结果(如下面的例子),分配一个向量只是为了立即将它变成一个字符串似乎很愚蠢.

例:

DWORD valueLength = 0;
DWORD type;
LONG errorCheck = RegQueryValueExW(
        hWin32,
        value.c_str(),
        NULL,
        &type,
        NULL,
        &valueLength);

if (errorCheck != ERROR_SUCCESS)
    WindowsApiException::Throw(errorCheck);
else if (valueLength == 0)
    return std::wstring();

std::wstring buffer;
do
{
    buffer.resize(valueLength/sizeof(wchar_t));
    errorCheck = RegQueryValueExW(
            hWin32,
            value.c_str(),
            NULL,
            &type,
            &buffer[0],
            &valueLength);
} while (errorCheck == ERROR_MORE_DATA);

if (errorCheck != ERROR_SUCCESS)
    WindowsApiException::Throw(errorCheck);

return buffer;
Run Code Online (Sandbox Code Playgroud)

我知道像这样的代码可能会略微降低可移植性,因为它意味着它std::wstring是连续的 - 但我想知道这个代码是多么不可移植.换句话说,编译器如何实际利用具有非连续内存的自由?


编辑:我更新了这个问题,提到C++ 03.读者应注意,在定位C++ 11时,标准现在要求basic_string是连续的,因此在定位该标准时,上述问题不是问题.

c++ string winapi stl c++03

32
推荐指数
2
解决办法
3480
查看次数

copy vs std :: move for thets

  • 在该示例中,默认副本和std :: move之间有什么区别?
  • move对象之后,新旧对象之间是否存在依赖关系?
int main () {

    int a = 100;
    std::cout<<&a<<std::endl;

    auto a_copy = a;                 // deduced as int
    std::cout<<&a_copy<<std::endl;

    auto a_move = std::move(a);      // deduced as int
    std::cout<<&a_move<<std::endl;

};
Run Code Online (Sandbox Code Playgroud)

输出:

0x7fffffffe094
0x7fffffffe098
0x7fffffffe09c
Run Code Online (Sandbox Code Playgroud)

c++ move-semantics c++11

25
推荐指数
4
解决办法
9710
查看次数

移动分配比复制分配慢 - 错误,功能还是未指定?

我最近意识到在C++ 11中添加移动语义(或者至少我的实现,Visual C++)已经积极地(并且非常显着地)打破了我的一个优化.

请考虑以下代码:

#include <vector>
int main()
{
    typedef std::vector<std::vector<int> > LookupTable;
    LookupTable values(100);  // make a new table
    values[0].push_back(1);   // populate some entries

    // Now clear the table but keep its buffers allocated for later use
    values = LookupTable(values.size());

    return values[0].capacity();
}
Run Code Online (Sandbox Code Playgroud)

我遵循这种模式来执行容器回收:我将重新使用相同的容器而不是销毁和重新创建它,以避免不必要的堆释放和(立即)重新分配.

在C++ 03上,这很好用 - 这意味着这段代码用于返回1,因为向量是按元素复制的,而它们的底层缓冲区保持原样.因此,我可以修改每个内部向量,因为它知道它可以使用与之前相同的缓冲区.

然而,在C++ 11上,我注意到这会导致右侧移动到左侧,这对左侧的每个向量执行元素移动分配.这反过来导致向量丢弃其旧缓冲区,突然将其容量减少到零.因此,由于堆分配/释放过多,我的应用程序现在会大大减慢速度.

我的问题是:这种行为是一个错误,还是故意的?是否甚至由标准指定?

更新:

我刚刚意识到这种特定行为的正确性可能取决于是否a = A()可以使指向元素的迭代器无效a.但是,我不知道移动赋值的迭代器失效规则是什么,所以如果你知道它们,你的答案中可能值得一提.

c++ performance memory-management move-semantics c++11

22
推荐指数
2
解决办法
1015
查看次数

为什么移动std :: optional不会重置状态

我很惊讶地得知移动构造函数(以及该事项的赋值)std::optional没有重置可选的移动,如[19.6.3.1/7]中所示,其中"bool(rhs)不变".

这也可以通过以下代码看出:

#include <ios>
#include <iostream>
#include <optional>
#include <utility>

int main() {
  std::optional<int> foo{ 0 };
  std::optional<int> bar{ std::move(foo) };

  std::cout << std::boolalpha
            << foo.has_value() << '\n'  // true
            << bar.has_value() << '\n'; // true
}
Run Code Online (Sandbox Code Playgroud)

这似乎与在标准库中移动的其他实例相矛盾,例如移动std::vector容器的位置通常以某种方式重置(在向量的情况下保证之后为空)以使其"无效",即使其中包含的对象也是如此他们自己已经离开了.这个或潜在的用例是否有任何理由支持,例如可能试图模仿相同类型的非可选版本的行为?

c++ optional c++17

20
推荐指数
3
解决办法
1793
查看次数

使用指向内部缓冲区的指针移动语义

假设我有一个管理指向内部缓冲区的指针的类:

class Foo
{
  public:

  Foo();

  ...

  private:

  std::vector<unsigned char> m_buffer;
  unsigned char* m_pointer;
};

Foo::Foo()
{
  m_buffer.resize(100);
  m_pointer = &m_buffer[0];
}
Run Code Online (Sandbox Code Playgroud)

现在,假设我也正确实现了3规则的东西,包括复制内部缓冲区的复制构造函数,然后将指针重新分配给内部缓冲区的新副本:

Foo::Foo(const Foo& f) 
{
  m_buffer = f.m_buffer;
  m_pointer = &m_buffer[0];
}
Run Code Online (Sandbox Code Playgroud)

如果我还实现了移动语义,那么只复制指针并移动缓冲区是否安全?

Foo::Foo(Foo&& f) : m_buffer(std::move(f.m_buffer)), m_pointer(f.m_pointer)
{ }
Run Code Online (Sandbox Code Playgroud)

在实践中,我知道这应该工作,因为std::vector移动构造函数只是移动内部指针 - 它实际上并没有重新分配任何东西,所以m_pointer仍然指向一个有效的地址.但是,我不确定标准是否可以保证这种行为.std::vector移动语义是否保证不会发生重新分配,因此向量的所有指针/迭代器都是有效的?

c++ vector move-semantics c++11

6
推荐指数
2
解决办法
2042
查看次数

将数据移入函数然后返回到它来自何处时,是否存在任何未定义的行为问题?

考虑以下功能:

std::vector<int> pushIt(std::vector<int> v){
    v.push_back(10);
    return v; 
}

int main(){
    std::vector<int> vec;
    vec = pushIt(std::move(vec));
}
Run Code Online (Sandbox Code Playgroud)

我的假设是向量移动到函数中,修改并移回其原始位置.这应该导致类似的行为,因为它作为非const引用传递.这似乎是非常有效的行为,但同事担心未定义的行为.这里有什么我想念的吗?

我想这样做是因为当前的功能

void currentPushIt(std::vector<int>& v){
    v.push_back(10);
}
Run Code Online (Sandbox Code Playgroud)

在代码审查中导致了很多问题,因为人们忽略了一个无辜的调用currentPushIt(v)会使迭代器失效的事实.让他们写作v=pushIt(std::move(v))应该唤醒他们他们不会犯同样的错误.

c++ move c++11

5
推荐指数
1
解决办法
168
查看次数

移动分配时左侧 std::vector 资源会发生什么变化?

我试图找出 C++ 11 标准是否允许std::vector释放接收移动分配的资源。

我给你举个例子:

std::vector<int> a {1, 2};
std::vector<int> b {3, 4};
a = std::move(b);
Run Code Online (Sandbox Code Playgroud)

现在我所期望的是,ab都包装了一个常规数组(通常)并且它们有一个指向它的指针,即a_ptrand b_ptr。现在我认为除其他外的移动分配确实如此a_ptr = b_ptr。标准是否保证在a_ptr此之前或通过此释放内存?

c++ memory-management vector move-semantics c++11

3
推荐指数
1
解决办法
158
查看次数

在从std :: vector移动时调用.clear(),. shrink_to_fit(),. empty()是否合法?

作为这两个问题的具体子句:

移动的向量是否总是空的?

移动物体怎么办?

人们不禁要问:是合法的调用.clear(),.chrink_to_fit(),.empty()在移动,从std::vector给它分配一个新的载体之前?我可以问一下,push_back()但我不知道会给出什么,因为依靠从向量移动的空是不安全的.

显而易见的是,破坏以及从新载体分配是合法的.

std::vector<int> fs = getVec();
giveVecs(std::move(fs));
fs.empty();  // 1.?
fs.size();   // 2.?
fs.shrink_to_fit(); // 3.?
fs.clear(); // //4. ?
fs = {} ; // 5. Should be fine, but weird when we have .clear()
fs.push_back(1); // 
Run Code Online (Sandbox Code Playgroud)

编辑:

我应该澄清,有些操作确实有前提条件:因此,(正如你可以在其他问题中看到的那样),并非所有操作在移动后都是合法的.

因此,我的问题可以这样重述:三种操作中的任何一种都有任何先决条件吗?问题的一个原因可能是与从对象移动的分配器相关的精细打印.

c++ c++14

0
推荐指数
1
解决办法
101
查看次数