标签: placement-new

"放置新"有什么用途?

有没有人曾经使用过C++的"贴牌新品"?如果是这样,那该怎么办?在我看来,它只对内存映射硬件有用.

c++ memory-management placement-new new-operator

385
推荐指数
18
解决办法
16万
查看次数

数组placement-new需要缓冲区中未指定的开销?

[expr.new]C++的5.3.4 2月草案给出了一个例子:

new(2,f) T[5]导致打电话operator new[](sizeof(T)*5+y,2,f).

这里,x和y是非负的未指定值,表示数组分配开销; new-expression的结果将从返回的值中抵消此数量operator new[].这种开销可以应用于所有数组新表达式,包括那些引用库函数operator new[](std::size_t, void*)和其他放置分配函数的表达式.开销的数量可能因新的一次调用而异.- 末端的例子 ]

现在来看以下示例代码:

void* buffer = malloc(sizeof(std::string) * 10);
std::string* p = ::new (buffer) std::string[10];
Run Code Online (Sandbox Code Playgroud)

根据上面的引用,第二行将new (buffer) std::string[10]在内部调用operator new[](sizeof(std::string) * 10 + y, buffer)(在构造单个std::string对象之前).问题是如果y > 0,预分配的缓冲区太小了!

那么我如何知道在使用数组放置时预先分配多少内存?

void* buffer = malloc(sizeof(std::string) * 10 + how_much_additional_space);
std::string* p = ::new (buffer) std::string[10];
Run Code Online (Sandbox Code Playgroud)

或者标准某处是否保证y == 0在这种情况下?报价再次说:

这种开销可以应用于所有数组新表达式,包括那些引用库函数operator …

c++ standards memory-management placement-new

62
推荐指数
4
解决办法
5787
查看次数

为什么C++ 17中没有std :: construct_at?

C++ 17补充说std::destroy_at,但没有任何std::construct_at对应物.这是为什么?难道不能像下面这样简单地实现吗?

template <typename T, typename... Args>
T* construct_at(void* addr, Args&&... args) {
  return new (addr) T(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

这样可以避免不完全自然的放置新语法:

auto ptr = construct_at<int>(buf, 1);  // instead of 'auto ptr = new (buf) int(1);'
std::cout << *ptr;
std::destroy_at(ptr);
Run Code Online (Sandbox Code Playgroud)

c++ placement-new c++17

58
推荐指数
4
解决办法
3055
查看次数

为什么这个程序中存在内存泄漏?在给定约束的情况下如何解决它(对包含 std::string 的对象使用 malloc 和 free)?

这是我在实际代码中遇到的问题的最小工作示例。

#include <iostream>

namespace Test1 {
    static const std::string MSG1="Something really big message";
}

struct Person{
    std::string name;
};

int main() {
    auto p = (Person*)malloc(sizeof(Person));
    p = new(p)Person();
    p->name=Test1::MSG1;

    std::cout << "name: "<< p->name << std::endl;

    free(p);

    std::cout << "done" << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我编译它并通过Valgrind运行它时,它给了我这个错误:

肯定丢失:1 个块中 31 个字节


约束条件

  1. 我一定会malloc在上面的示例中使用,因为在我的实际代码中,我在 C++ 项目中使用了 C 库,该项目malloc在内部使用了它。所以我无法摆脱malloc使用,因为我没有在代码中的任何地方明确地这样做。
  2. 我需要在我的代码中一次又一次地重新std::string name分配。Person

c++ valgrind memory-leaks placement-new dynamic-memory-allocation

58
推荐指数
5
解决办法
5415
查看次数

C++,是否可以直接调用构造函数,而不需要新的?

new如果我已经有对象的内存,我可以显式调用构造函数而不使用吗?

class Object1{
    char *str;
public:
    Object1(char*str1){
        str=strdup(str1);
        puts("ctor");
        puts(str);
    }
    ~Object1(){
        puts("dtor");
        puts(str);
        free(str);
    }
};

Object1 ooo[2] = {
     Object1("I'm the first object"), Object1("I'm the 2nd")
};

do_smth_useful(ooo);
ooo[0].~Object1(); // call destructor
ooo[0].Object1("I'm the 3rd object in place of first"); // ???? - reuse memory
Run Code Online (Sandbox Code Playgroud)

c++ constructor placement-new

51
推荐指数
4
解决办法
3万
查看次数

将空指针传递给placement new

默认的放置new运算符在18.6 [support.dynamic]1中声明,带有非抛出异常规范:

void* operator new (std::size_t size, void* ptr) noexcept;
Run Code Online (Sandbox Code Playgroud)

这个函数没有任何作用,除非return ptr;它是合理的noexcept,但是根据5.3.4 [expr.new]15这意味着编译器必须检查它在调用对象的构造函数之前不返回null:

-15-
[ 注意:除非使用非抛出异常规范(15.4)声明分配函数,否则它表示无法通过抛出std::bad_alloc异常来分配存储(第15,18.6.2.1节); 否则返回非空指针.如果使用非抛出异常规范声明分配函数,则返回null以指示无法分配存储,否则返回非空指针.-end note ]如果分配函数返回null,则不进行初始化,不应调用解除分配函数,并且new-expression的值应为null.

在我看来(特别是对于放置new,而不是一般)这个空检查是一个不幸的性能命中,尽管很小.

我一直在调试一些代码,其中new在一个性能敏感的代码路径中使用了放置,以改进编译器的代码生成,并在程序集中观察到null检查.通过提供new使用抛出异常规范声明的特定于类的放置重载(即使它不可能抛出),删除了条件分支,这也允许编译器为周围的内联函数生成更小的代码.说放置new函数的结果可能会抛出,即使它不能,也是可测量的更好的代码.

所以我一直想知道是否真的需要进行空检查new.它返回null的唯一方法是将它传递给null.尽管写下来是可能的,而且显然是合法的:

void* ptr = nullptr;
Obj* obj = new (ptr) Obj();
assert( obj == nullptr );
Run Code Online (Sandbox Code Playgroud)

我不明白为什么这将是有益的,我认为它会更好,如果程序员有明确使用放置前检查null new

Obj* obj = ptr ? new (ptr) Obj() : nullptr;
Run Code Online (Sandbox Code Playgroud)

有没有人需要放置new来正确处理空指针的情况?(即不添加作为ptr有效内存位置的显式检查.)

我想知道禁止将空指针传递给默认的放置 …

c++ placement-new micro-optimization noexcept

42
推荐指数
1
解决办法
3350
查看次数

C++中的"重新绑定"引用是否合法?

C++中的以下内容是否合法?

据我所知,Reference有一个简单的析构函数,所以它应该是合法的.
但我认为参考不能合法反弹......可以吗?

template<class T>
struct Reference
{
    T &r;
    Reference(T &r) : r(r) { }
};

int main()
{
    int x = 5, y = 6;
    Reference<int> r(x);
    new (&r) Reference<int>(y);
}
Run Code Online (Sandbox Code Playgroud)

c++ reference placement-new language-lawyer

38
推荐指数
3
解决办法
1631
查看次数

malloc&placement new vs. new

过去几天我一直在研究这个问题,到目前为止,除了教条论点或对传统的诉求之外,我还没有真正找到任何令人信服的东西(即"它是C++方式!").

如果我正在创建一个对象数组,使用时有什么令人信服的理由(除了易用性):

#define MY_ARRAY_SIZE 10

//  ...

my_object * my_array=new my_object [MY_ARRAY_SIZE];

for (int i=0;i<MY_ARRAY_SIZE;++i) my_array[i]=my_object(i);
Run Code Online (Sandbox Code Playgroud)

过度

#define MEMORY_ERROR -1
#define MY_ARRAY_SIZE 10

//  ...

my_object * my_array=(my_object *)malloc(sizeof(my_object)*MY_ARRAY_SIZE);
if (my_object==NULL) throw MEMORY_ERROR;

for (int i=0;i<MY_ARRAY_SIZE;++i) new (my_array+i) my_object (i);
Run Code Online (Sandbox Code Playgroud)

据我所知,后者比前者更有效(因为你没有不必要地将内存初始化为一些非随机值/调用默认构造函数),唯一的区别就在于你清理了一个:

delete [] my_array;
Run Code Online (Sandbox Code Playgroud)

另一个你清理:

for (int i=0;i<MY_ARRAY_SIZE;++i) my_array[i].~T();

free(my_array);
Run Code Online (Sandbox Code Playgroud)

我出于一个令人信服的理由.上诉的事实,这是C++(不是C),因此mallocfree不应使用不-据我可以告诉- 引人注目的一样,因为它是教条主义.是否有一些我缺少的东西new []优于malloc

我的意思是,就我所知,你根本不能使用new []- 根本没有 - 创建一个没有默认的无参数构造函数的数组,而这个malloc方法可以这样使用.

c++ malloc placement-new new-operator

37
推荐指数
6
解决办法
5973
查看次数

使用相同的变量销毁然后构造新对象

有时重新开始很好.在C++中,我可以使用以下简单的操作:

{

    T x(31, Blue, false);

    x.~T();                        // enough with the old x

    ::new (&x) T(22, Brown, true); // in with the new!

    // ...
}
Run Code Online (Sandbox Code Playgroud)

在范围的最后,析构函数将再次运行,一切似乎都很好.(我们也说T有点特别,不喜欢被分配,更不用说交换了.)但有些东西告诉我,摧毁一切并再试一次并不总是没有风险.这种方法有可能存在吗?

c++ placement-new

28
推荐指数
4
解决办法
1899
查看次数

为什么在析构函数可以不显式调用构造函数?

在下面的C++代码中,我可以显式调用析构函数而不是构造函数.这是为什么?不明确的ctor调用与dtor案件更具表现力统一性吗?

class X { };

int main() {
  X* x = (X*)::operator new(sizeof(X));
  new (x) X;  // option #1: OK
  x->X();     // option #2: ERROR

  x->~X();
  ::operator delete(x);
}
Run Code Online (Sandbox Code Playgroud)

c++ constructor destructor placement-new explicit-destructor-call

28
推荐指数
2
解决办法
3130
查看次数